JDK8 Stream流的用法
Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返.
流的操作类型分为两种:
在对于一个 Stream 进行多次转换操作 (Intermediate 操作),每次都对 Stream 的每个元素进行转换,而且是执行多次,这样时间复杂度就是 N(转换次数)个 for 循环里把所有操作都做掉的总和吗?其实不是这样的,转换操作都是 lazy 的,多个转换操作只会在 Terminal 操作的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream 里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在 Terminal 操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。
当把一个数据结构包装成 Stream 后,就要开始对里面的元素进行各类操作了。常见的操作可以归类如下。
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit
// filter
list.stream().filter(e -> e.getAge() == 10).forEach(e -> System.out.println(e));
2. Stream map(Function<? super T, ? extends R> mapper)
根据给定的function做转换
// map
Function<People, String> nameFun = (e) -> e.getName();
list.stream().map(nameFun).forEach(e -> System.out.println(e));
JDK自带了一些基本类型的map函数
IntStream mapToInt(ToIntFunction<? super T> mapper);
LongStream mapToLong(ToLongFunction<? super T> mapper);
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
3. Stream flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
flatMap 把 input Stream 中的层级结构扁平化,就是将最底层元素抽出来放到一起
// flatmap
Stream<List> inputStream = Stream.of(Arrays.asList(1), Arrays.asList(2, 3),
Arrays.asList(4, 5, 6));
Stream outputStream = inputStream.flatMap((childList) -> childList.stream());
outputStream.forEach(e -> System.out.println(e));
IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
4. Stream distinct()
对于Stream中包含的元素进行去重操作(去重逻辑依赖元素的equals方法),新生成的Stream中没有重复的元素
5. Stream peek(Consumer<? super T> action)
对流中的每个元素做特定的操作并返回原先的流
// peak
Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6, 1, 2, 3))
.flatMap((childList) -> childList.stream()).peek(e -> System.out.println(“—” + e)).count();
6.void forEach(Consumer<? super T> action)
对流中的每个元素做操作。这是一个流的结束操作。
// peak
Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6, 1, 2, 3))
.flatMap((childList) -> childList.stream()).peek(e -> System.out.println(“—” + e)).count();
7. Object[] toArray()
返回一个由stream包含所有元素的数组。
Stream s = Stream.of(1,2,3);
Object[] oarr = s.toArray();
for(Object obj:oarr){
System.out.println(obj);
}
8. Reduce
T reduce(T identity, BinaryOperator accumulator);
Optional reduce(BinaryOperator accumulator);
U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator combiner);
这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。例如 Stream 的 sum 就相当于
Integer sum = integers.reduce(0, (a, b) -> a+b); 或
Integer sum = integers.reduce(0, Integer::sum);
也有没有起始值的情况,这时会把 Stream 的前面两个元素组合起来,返回的是 Optional。
//reduce
String concat = Stream.of(“A”, “B”, “C”, “D”).reduce(“”, String::concat);
System.out.println(concat);
double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
System.out.println(minValue);
int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
System.out.println(sumValue);
sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
concat = Stream.of(“a”, “B”, “c”, “D”, “e”, “F”).filter(x -> x.compareTo(“Z”) > 0).reduce(“”, String::concat);
Stream的reduce方法,其实就是聚合或者汇聚的意思,由于Stream本身就代表着一堆数据,那stream.reduce()方法顾名思义就是把一堆数据聚合成一个数据。
9. Match
Stream 有三个 match 方法,从语义上说:
allMatch:Stream 中全部元素符合传入的 predicate,返回 true
anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true
noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
//code
List persons = new ArrayList();
persons.add(new Person(1, “name” + 1, 10));
persons.add(new Person(2, “name” + 2, 21));
persons.add(new Person(3, “name” + 3, 34));
persons.add(new Person(4, “name” + 4, 6));
persons.add(new Person(5, “name” + 5, 55));
boolean isAllAdult = persons.stream().
allMatch(p -> p.getAge() > 18);
System.out.println(“All are adult? ” + isAllAdult);
boolean isThereAnyChild = persons.stream().
anyMatch(p -> p.getAge() < 12);
System.out.println(“Any child? ” + isThereAnyChild);
总之,Stream 的特性可以归纳为: