Stream是java8的新增特性,表示数据流。
filter
、map
是延迟执行的,只有到了终点操作才会将操作顺序执行。limit(n)
、findFirst()
)可以实现“短路操作”,访问到有限的元素后就可以返回。所有的流操作都可以串行执行或者并行执行。除非显示的创建并行流,否则默认创建串行流。
串行:Collection.stream()
、IntStream.range(int, int)
并行:Collection.parallelStream()、
通过
parallel()
方法可以将串行流转换为并行流,sequential()
方法将流转换为串行流
流可以从非线程安全的集合中创建。当流执行时,非并发的数据源不应该改变,否则会抛出java.util.ConcurrentModificationException
异常。
大部分流的操作的参数都是函数式接口,可以使用Lambda表达式实现。它们用来描述用户的行为,称之为行为参数(behavioral parameters)。
如果这些行为参数有状态,则流的操作的结果可能是不确定的,比如下面的代码:
下面代码在并行执行时,由于执行顺序的不确定性,state.s的改变时机可能不同,导致多次执行时的结果不同
List<String> l = new ArrayList(Arrays.asList("one", "two", ……)); class State { boolean s; } final State state = new State(); Stream<String> sl = l.stream().map(e -> { if (state.s) return "OK"; else { state.s = true; return e; } }); sl.forEach(System.out::println);
某些流的返回元素是有确定顺序的。这取决于它的数据源和中间操作。
比如List和Array创建的流是有序的,而HashSet创建的流是无序的。
sort()
方法可以将流变得有序,而unordered()
可以将流无序(不会打散元素)
当流有序时,如果用户并不关心顺序,可以使用unordered
显示的去掉流的有序约束,可以改善某些情况下的并行性能
常见创建流的方法:
Stream()
或parallelStream()
:如list.parallelStream()、Arrays.asList(1,2,3).stream()。Arrays.stream(Object[])
方法:如Arrays.stream(new int[]{1,2,3})。Stream.of(Object[])
、IntStream.range(int, int)
、Stream.iterate(Object, UnaryOperator)。
Random.ints()
。中间操作是延迟执行的,不会修改原始数据流,在终点操作开始时才会开始执行
根据流中元素的hashCode()
和equals()
方法去除重复元素
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6); list.stream().distinct().forEach(System.out::print); // 123456 System.out.println(); list.forEach(System.out::print); // 12344456
接收predicate
,过滤数据
// 筛选出偶数 List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6); list.stream().filter(e -> e % 2 == 0).forEach(System.out::print); // 24446
接收一个Function
实例,重新印射数据
// 加1 List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6); list.stream().map(e -> e + 1).forEach(System.out::print); // 23455567
类似map,不过结果一定要是Double类型。
类似的方法还有mapToInt()
,mapToLong()
// 加1.1 List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6); list.stream().mapToDouble(e -> e + 1.1).forEach(System.out::println); /* 2.1 3.1 4.1 5.1 5.1 5.1 6.1 7.1 */ // 加1 List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6); list.stream().mapToDouble(e -> e + 1).forEach(System.out::println); /* 2.0 3.0 4.0 5.0 5.0 5.0 6.0 7.0 */
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
将映射后的元素放在一个新的流中。
类似的方法还有flatMapToDouble
、flatMapToInt
、flatMapToLong
List<String> list = Arrays.asList("1233", "2444", "562","78"); list.stream() .flatMap(e -> Arrays.stream(e.split("2"))) .forEach(System.out::println); /* 1 33 444 56 78 */
限制流中元素的数量。对于有序并行流,性能消耗更高
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6); list.stream().limit(5).forEach(System.out::print); // 12344
丢弃前n个元素,返回流。
System.out.println("-----------------------"); list.stream().skip(6).forEach(System.out::println); System.out.println("-----------------------"); list.stream().skip(8).forEach(System.out::println); /* 7 5 ----------------------- ----------------------- */
接收一个Consumer,对元素做某些操作,但是并不会修改数据(对象数据可能会被修改)。一般用于debug
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5); list.stream().peek(System.out::print).count(); // 810975
将流中的元素按自然顺序排序。可以自定义比较器。
System.out.println("升序: "); List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5); list.stream().sorted().forEach(System.out::print); System.out.println(); System.out.println("降序: "); list.stream().sorted((x, y) -> y - x).forEach(System.out::print); /* 升序: 015789 降序: 987510 */
有allMatch(Predicate p)
、anyMatch(Predicate p)
、noneMatch(Predicate p)
三种方法。
返回boolean。
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5); // allMatch 是否全部符合 System.out.println(list.stream().allMatch(x -> x > -1)); // true System.out.println(list.stream().allMatch(x -> x > 1)); // false // anyMatch 是否至少有一个符合 System.out.println(list.stream().anyMatch(x -> x == -1)); // false System.out.println(list.stream().anyMatch(x -> x == 1)); // true // noneMatch 是否全部不符合 System.out.println(list.stream().noneMatch(x -> x > 5)); // false System.out.println(list.stream().noneMatch(x -> x > 9)); // true
返回流中元素的数量。返回long
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5); System.out.println(list.stream().count()); // 6
传入Collectors中的接口实现,将流转化为其他形式的数据。部分接口:
toList
、toSet
转化为list或setcounting
计数reducing
化简maxBy
、minBy
最大值最小值summingInt
求和joining
字符串连接List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5); // 转化为list格式 List<Integer> res1 = list.stream().collect(Collectors.toList()); // 转化为set格式 Set<Integer> res2 = list.stream().collect(Collectors.toSet());
有findFirst()和findAny()两种。返回Optional对象
Optional<T> findFirst();
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5); Optional<Integer> integer = list.stream().findFirst(); System.out.println(integer.get()); // 8 // findAny()对于串行流:一般返回第一个结果 integer = list.stream().findAny(); System.out.println(integer.get()); // 8 // findAny()对于并行流,多次执行会随机返回结果 integer = list.parallelStream().findAny(); System.out.println(integer.get()); // 随机打印
遍历流中元素,执行指定操作
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5); List<Integer> res = new ArrayList<>(); list.stream().forEach(e -> res.add(e + 2)); System.out.println(list.toString()); // [10, 3, 2, 11, 9, 7]
最大值、最小值。返回Optional对象
将元素按比较器排序,然后min返回第一个数,max返回最后一个数
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5); // 升序排序 015789 System.out.println(list.stream().min((x, y) -> x - y).get()); // 0 System.out.println(list.stream().max((x, y) -> x - y).get()); // 9 // 降序排序 987510 System.out.println(list.stream().min((x, y) -> y - x).get()); // 9 System.out.println(list.stream().max((x, y) -> y - x).get()); // 0
将元素数据结合后返回。
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5); // 默认返回Optional类型数据 Optional<Integer> res1 = list.stream().reduce(Integer::sum); System.out.println(res1.get()); // 指定返回数据类型为Integer Integer res2 = list.stream().reduce(0, Integer::sum); System.out.println(res2);
将流中的元素保存到数组中
<A> A[] toArray(IntFunction<A[]> generator);
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5); Integer[] ints = list.stream().map(e -> e + 1).toArray(Integer[]::new); for (Integer integer : ints) { System.out.println(integer); } /* 9 2 1 10 8 6 */