stream流是为了方便操作集合和数组的,与Lambda表达式配合
流的操作可以分为两种类型
- 中间操作,可以有多个,每次返回一个新的流,可以进行链式操作,不可变性,不会修改原始数据源,也不会产生中间状态或副作用,每次返回一个新的流对象,保证数据的不可变性。
- 终端操作,只能有一个,每次执行完,流便关闭,这里要注意中间操作不会立即执行,只有到了终端操作,流才真正的开始遍历执行,也就是一次遍历执行多个操作,性能提升,也就是惰性要求。
首先创建流
1.数组:Arrays.stream()或者stream.of()创建流。查看of()方法源码发现其内部其实调用了Arrays.stream()方法,通过此方法将一组元素转换成Stream对象。
public static<T> Stream<T> of(T... values) {
return Arrays.stream(values);
}
2.集合可以直接使用stream()方法创建流,因为该方法在Collection接口中。(集合还可以调用parallelStream()并行流,但我不会)
操作流
在此之前补充:java8新特性,新增函数式接口,下面是四个常见的接口
-
Consumer:消费型接口,接受一个输入参数并且无返回值类型。
-
Predicate:判断型接口,其中有一个test()的抽象方法,接受一个输入参数,返回一个布尔值结果。
public interface Predicate<T> { boolean test(T t);``` -
Supplier:供给型接口,无参数,返回一个结果。
-
Function<T,R>:函数式接口,其中有一个抽象方法,第一个泛型接受一个输入参数,第二个泛型返回一个结果。
public interface Function<T, R> { R apply(T t);
1.过滤filter():中间操作 接受一个Predicate函数作为参数,用于过滤Stream流中的元素,只有满足Predicate条件的元素会被保留下来
stream.filter(new Predicate<Student>() {
@Override
public boolean test(Student student) {
return student.getScore()>70;\\这里可以简写下文再说
}
}).forEach(System.out::println);
映射Map():中间操作 接受一个Function函数作为参数,用于对流中的元素进行映射转换,对每个元素应用apply方法后的返回值构成一个新的Stream流。
```
stream.map(new Function<Student, Integer>() {
@Override
public Integer apply(Student student) {
return student.getScore()+10;//下文重写
}
}).forEach(System.out::println);
```
flatMap
排序操作sorted:中间操作
对流中的数据进行排序,默认自然排序,或者传进一个比较器进行排序。自然排序通过排序对象实现Comparable 接口,实现compareTo方法,如果i=0, 也表明对象x与y排位上是相等的(并非意味x.equals(y) = true, 但是jdk api上强烈建议这样处理)如果返回数值>0,则调用对象大于参数对象(下一个对象),反之,调用者小于参数对象。=则相等。
```java
@Override
public int compareTo(Student o) {
return this.score-o.score;
}
```
第二种用法,传入一个比较器comparator,指定排序规则进行排序
@Override
public int compare(Student o1, Student o2) {
return o1.getScore()-o2.getScore() !=0 ?o1.getScore()-o2.getScore():o1.getId()-o2.getId();
}
}).forEach(System.out::println);
去重Distinct:中间操作
根据元素的equals() 和 hashCode() 方法来判断是否重复
截断操作limit和skip:中间操作
limit(n)保留流中的前n个元素,返回一个包含最多n个元素的新流,若流中的元素少于n个返回原始流
skip(n)跳过流的前n个元素,返回包含剩余元素的新流,若流中元素少于n返回空流。
组合流concat Stream中静态方法,返回一个新的流
终端操作
匹配操作 allMatch, anyMatch,noneMatch
统计个数count()统计流中元素个数返回long值
查找第一个findFirst()返回一个Optional对象
查造某一个findAny()返回一个Optional对象
lamdba表达式语法精简
-
参数类型可以省略,若省略,每个参数类型都需要省略
-
参数的小括号里面只有一个参数,小括号省略
-
如果方法体中只有一句代码,大括号省略
-
若方法体只有一句代码,且是return那么大括号省略且去掉return lambda表达式由三部分组成:参数列表,->,方法体。其本质是一个匿名内部类有一个抽象方法,重写这个方法。 lambda表达式对接口要求,接口定义的必须要实现的抽象方法只能是一个。 lambda的进阶方法引用 若存在一种情况,我们新建了多个接口的实现对象,其方法都是相同的,我们的接口方法需要修改,那么都需要更改,现在提供一种更高效的简写方法。方法引用的定义是:快速将一个lambda表达式的实现指向一个已经写好的方法。 语法说明:方法隶属者::方法名(静态方法隶属者类,非静态方法隶属者对象,隶属者不是接口,而是定义引用方法的类或者对象) 注意事项: 1. 被引用的方法参数数量以及类型要和接口中的