java Stream
1.简介
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
2.构建Stream流
集合类型通过.Stream()方法转换为Stream流
List<String> list= new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
list.add("郭七");
list.add("王勃");
Stream<String> stream = list.stream();
3.Stream流的常用操作
(1)forEach循环
通过forEach()方法来遍历流中的数据,属于终结方法,后面不能再调用别的流操作
List<String> list= new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
list.add("郭七");
list.add("王勃");
Stream<String> stream = list.stream();
stream.forEach(System.out::println);//打印流中的数据
结果: 张三
李四
王五
赵六
郭七
王勃
forEach()
方法接收的是一个 Consumer(Java 8 新增的一个函数式接口,接受一个输入参数并且无返回的操作)类型的参数,类名 :: 方法名
是 Java 8 引入的新语法,System.out
返回 PrintStream 类,println 方法你应该知道是打印的。
(2)filter过滤
通过 filter()
方法可以从流中筛选出我们想要的元素
List<String> list= new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
list.add("郭七");
list.add("王勃");
Stream<String> stream = list.stream();
stream.filter(name->name.startsWith("王"))//过滤流中"王"开头的数据
.forEach(System.out::println);//打印流中的数据
结果:王五
王勃
filter()
方法接收的是一个 Predicate(Java 8 新增的一个函数式接口,接受一个输入参数返回一个布尔值结果)类型的参数,因此,我们可以直接将一个 Lambda 表达式传递给该方法,比如说 element -> element.startsWith("王")
就是筛选出“王”开头的字符串。
(3)map映射
如果想通过某种操作把一个流中的元素转化成新的流中的元素,可以使用 map()
方法。
List<String> list= new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
list.add("郭七");
list.add("王勃");
Stream<String> stream = list.stream();
stream.map(name->name=name.substring(1))//将姓名映射为不带姓的名字
.forEach(System.out::println);//打印流中的数据
结果:三
四
五
六
勃
(4)Match匹配
Stream 类提供了三个方法可供进行元素匹配,它们分别是:
anyMatch()
,只要有一个元素匹配传入的条件,就返回 true。allMatch()
,只有有一个元素不匹配传入的条件,就返回 false;如果全部匹配,则返回 true。noneMatch()
,只要有一个元素匹配传入的条件,就返回 false;如果全部匹配,则返回 true。
public class MatchStreamDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("周杰伦");
list.add("王力宏");
list.add("陶喆");
list.add("林俊杰");
boolean anyMatchFlag = list.stream().anyMatch(element -> element.contains("王"));
boolean allMatchFlag = list.stream().allMatch(element -> element.length() > 1);
boolean noneMatchFlag = list.stream().noneMatch(element -> element.endsWith("沉"));
System.out.println(anyMatchFlag);
System.out.println(allMatchFlag);
System.out.println(noneMatchFlag);
}
}
因为“王力宏”以“王”字开头,所以 anyMatchFlag 应该为 true;因为“周杰伦”、“王力宏”、“陶喆”、“林俊杰”的字符串长度都大于 1,所以 allMatchFlag 为 true;因为 4 个字符串结尾都不是“沉”,所以 noneMatchFlag 为 true。
程序输出的结果如下所示:
true
true
true
(5)reduce组合
reduce()
方法的主要作用是把 Stream 中的元素组合起来,它有两种用法:
Optional reduce(BinaryOperator accumulator)
没有起始值,只有一个参数,就是运算规则,此时返回 Optional。
T reduce(T identity, BinaryOperator accumulator)
有起始值,有运算规则,两个参数,此时返回的类型和起始值类型一致。
来看下面这个例子。
public class ReduceStreamDemo {
public static void main(String[] args) {
Integer[] ints = {0, 1, 2, 3};
List<Integer> list = Arrays.asList(ints);
Optional<Integer> optional = list.stream().reduce((a, b) -> a + b);
Optional<Integer> optional1 = list.stream().reduce(Integer::sum);
System.out.println(optional.orElse(0));
System.out.println(optional1.orElse(0));
int reduce = list.stream().reduce(6, (a, b) -> a + b);
System.out.println(reduce);
int reduce1 = list.stream().reduce(6, Integer::sum);
System.out.println(reduce1);
}
}
运算规则可以是 Lambda 表达式(比如 (a, b) -> a + b
),也可以是类名::方法名(比如 Integer::sum
)。
程序运行的结果如下所示:
6
6
12
12
0、1、2、3 在没有起始值相加的时候结果为 6;有起始值 6 的时候结果为 12。
4.Stream流转换
既然可以把集合或者数组转成流,那么也应该有对应的方法,将流转换回去——collect()
方法就满足了这种需求。
public class CollectStreamDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("周杰伦");
list.add("王力宏");
list.add("陶喆");
list.add("林俊杰");
List<Integer> list1 = list.stream().map(String::length).collect(Collectors.toList());
System.out.println(list1);
String str = list.stream().collect(Collectors.joining(", ")).toString();
System.out.println(str);
}
}