学习Stream的目的
-
函数式编程渐渐变成主流,为了看懂同事的代码。
-
相对于传统的编程方式,代码更为简洁清晰易懂。
-
使得并发编程变得如此简单。
-
有效的避免了代码嵌套地狱。(见样例)
if (条件1) { if (条件2) { if (条件3) { // 再嵌套下去都快见到Diablo了。 } } }
Stream的特点
- 不修改数据源:任何对于Stream对象的操作都不会修改数据源的数据。
- 延迟执行:中间操作只是对于一系列操作细节的定义,而非执行。只有在终端操作被调用的同时执行中间操作。
- 可消费:任何一个Stream对象执行了终端操作后都将不可再利用。只能操作由数据源生成的新的Stream。
Stream的分类
-
串行流:单项环境下的Stream,基础。
List.of().stream();
-
并行流:多线程环境下的Stream,重点难点。本文中未涉及。
List.of().parallelStream();
Stream对象的创建
总共有三种方式:
-
经由集合对象创建
List<String> list = new ArrayList<>(); Stream<String> stream = list.stream();
-
经由数组对象创建(两种)
String[] strs = new String[10]; // 将数组所有元素装入stream Stream<String> stream1 = Arrays.stream(strs); // 将数组指定区间的元素装入stream Stream<String> stream2 = Arrays.stream(strs, 1, 7);
-
使用Stream的静态方法创建(三种)
// 由单个元素创建Stream,元素不允许为null Stream<String> stream1 = Stream.of("Test"); // 由单个元素创建stream,元素允许为null Stream<String> stream2 = Stream.ofNullable(null); // 由多个元素创建stream,内部其实调用的是Arrays.stream(T[] array) Stream<String> stream3 = Stream.of("Test1", "Test2", "Test3");
方法的分类
- 中间操作:根据调用的方法,返回各种各样的stream对象。传入的各种Lambda只是修改了该对象中对应方法的定义,而非执行。
- 终端操作:执行终端操作的方法,并且其间也执行中间操作对应的方法。
常用方法(入门)
中间操作
distinct
方法签名:Stream<T> distinct()
作用:返回一个去重后的Stream。
List<String> list = List.of("1", "1");
list.stream().distinct()
.forEach(t -> System.out.println(t)); // 输出:1
filter
方法签名:Stream<T> filter(Predicate<? super T> predicate)
作用:返回一个由满足predicate条件的元素构成的Stream。
List<Integer> list = List.of(1, 3, 5);
list.stream().filter(t -> t >= 3)
.forEach(t -> System.out.println(t)); // 输出:3, 5
sorted
因为sorted存在两种重载,并且在jdk源码的实现并不相同,所以我们分开讨论。
方法签名:Stream<T> sorted()
作用:通过调用T类型重写Comparable接口的compareTo方法排序,返回排序后的Stream。
// 此处省略了一些java文件定义的结构,请着眼于一下核心代码
// NG例, 不实现Comparable接口
class MyInteger {
int value;
MyInteger(int value) {
this.value = value;
}
}
List<MyInteger> list = new ArrayList<>();
list.add(new MyInteger(4));
list.add(new MyInteger(1));
list.add(new MyInteger(3));
list.stream().sorted() // 不报错
.forEach(t -> System.out.println(t.value)); // ClassCastException:不能被强转成Comparable类型
// OK例, 实现Comparable接口(Integer实现了Comparable接口)
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().sorted()
.forEach(t -> System.out.println(t)); // 输出:1 3 4
方法签名:Stream<T> sorted(Comparator<? super T> comparator)
作用:通过调用传入的comparator的compare方法排序,返回排序后的Stream。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().sorted((o1, o2) -> o2 - o1) // 传入一个比较器的实现
.forEach(t -> System.out.println(t.value)); // 输出:4 3 1
skip
方法签名:Stream<T> skip(long n)
作用:返回一个不包含前n项的Stream。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().skip(2) // 跳过前两个元素
.forEach(t -> System.out.println(t.value)); // 输出:3
limit
方法签名:Stream<T> limit(long n)
作用:返回一个包含前n项的Stream。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().limit(2) // 跳过前两个元素
.forEach(t -> System.out.println(t.value)); // 输出:4 1
peek
方法签名:Stream<T> peek(Consumer<? super T> action)
作用:执行消费操作,返回原Stream。虽然有消费操作,但是Stream的状态并不会改变。并不会真正消费Stream这一特点是的peek方法常用于调试。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Stream<Integer> stream = list.stream();
stream.peek(t -> System.out.println(t)); // 输出:4 1 3, 并且不消费stream
stream.forEach(t -> System.out.println(t)); // 输出:4 1 3, 并且消费stream(消费后stream不可再次使用)
stream.forEach(t -> System.out.println(t)); // IllegalStateException:stream已经被操作或关闭
map
方法签名:Stream<T> map(Function<? super T, ? extends R> mapper)
作用:将原Stream中的所有元素类型从T转化为R(不是强转,是通过一些操作得到R类型),返回封装R类型元素的Stream。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().map(t -> String.valueOf(t)) // 将元素都转换成String
.forEach(t -> System.out.println(t)); // 输出:4 1 3
flatMap
方法签名:Stream<T> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
作用:将原Stream中的所有元素类型从T转化为R,返回Stream<R>。与map的主要区别在于,适配一对多的数据类型。比如,类型T中存在一个List<String>,使用map返回一个Stream<List<String>>,而是用flatMap则返回一个Stream<String>,实现一对多的映射。
List<Integer[]> list = new ArrayList<>();
list.add(new Integer[] {1, 2, 3});
list.add(new Integer[] {4, 5, 3});
list.stream().flatMap(t -> Stream.of(t)) // 将各个数组中的元素都放入stream, 实现 1 → n 的转换
.forEach(t -> System.out.println(t)); // 输出:1 2 3 4 5 3
终端操作
forEach
方法签名:void forEach(Consumer<? super T> action)
作用:迭代消费Stream里的所有元素,比如打印,写入文件,写入DB等。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().forEach(t -> System.out.println(t)); // 输出:4 1 3
toArray
方法签名:Object[] toArray()
作用:将Stream中的所有元素封装成Object[]返回。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Object[] objects = list.stream().toArray(); // 与元素类型无关, 固定返回Object[]
Integer[] ints = (Integer[])objects; // 使用时你可能需要类型强转
count
方法签名:long count()
作用:返回Stream中的元素个数。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
long count = list.stream().count(); // 返回stream中的元素个数, 当前为3
findFirst
方法签名:Optional<T> findFirst()
作用:Stream的第一个元素封装在Optional中返回。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> first = list.stream().findFirst(); // 返回stream中的第一个元素, 当前为4
/*
Optional类内容比较多所以现在不做赘述, 大家姑且就认为是个只能存放一个元素的容器就好,以后会开一个新的博文详细为 大家讲解用法
*/
anyMatch
方法签名:boolean anyMatch(Predicate<? super T> predicate)
作用:当存在符合predicate条件的元素时返回true,否则返回false。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
boolean bool = list.stream().anyMatch(t -> t <= 1); // 当一个元素小于等于1时就返回true, 当前true
allMatch
方法签名:boolean allMatch(Predicate<? super T> predicate)
作用:当所有元素都符合predicate条件时返回true,否则返回false。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
boolean bool = list.stream().allMatch(t -> t <= 1); // 当所有元素小于等于1时才返回true, 当前false
noneMatch
方法签名:boolean noneMatch(Predicate<? super T> predicate)
作用:当所有元素都不符合predicate条件时返回true,否则返回false。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
boolean bool = list.stream().noneMatch(t -> t <= 1); // 当所有元素都不小于等于1时才返回true, 当前false
min
方法签名:Optional<T> min(Comparator<? super T> comparator)
作用:按照传入的比较器将最小的元素封装在Optional中返回。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> min = list.stream().min((o1, o2) -> o2 - o1); // 根据传入的比较器实现返回最小值, 当前4
/*
这个方法可以认为stream按照传入的比较器排序, 返回排序后的第一个元素
*/
max
方法签名:Optional<T> max(Comparator<? super T> comparator)
作用:按照传入的比较器将最大的元素封装在Optional中返回。
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> max = list.stream().max((o1, o2) -> o2 - o1); // 根据传入的比较器实现返回最大值
/*
这个方法可以认为stream按照传入的比较器排序, 返回排序后的最后一个元素
*/
本文只讨论了串行流的使用方法,对于并行流等进阶的使用方法请参考 Java -> Stream进阶(尚未更新)
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/282263.html