创建流

  1. 集合
    这种数据源较为常用,通过stream()方法即可获取流对象:

    1. List<Person> list = new ArrayList<Person>();
    2. Stream<Person> stream = list.stream();
  2. 数组
    通过Arrays类提供的静态函数stream()获取数组的流对象:

    1. String[] names = {"chaimm","peter","john"};
    2. Stream<String> stream = Arrays.stream(names);

  3. 直接将几个值变成流对象:

    1. Stream<String> stream = Stream.of("chaimm","peter","john");
  4. 文件

    1. try(Stream lines = Files.lines(Paths.get(“文件路径名”),Charset.defaultCharset()))
    2. {
    3. //可对lines做一些操作
    4. }catch(IOException e){
    5. }
  5. iterator
    创建无限流

    1. Stream.iterate(0, n -> n + 2)
    2. .limit(10)
    3. .forEach(System.out::println);

    筛选 filter

    filter 函数接收一个Lambda表达式作为参数,该表达式返回boolean,在执行过程中,流将元素逐一输送给filter,并筛选出执行结果为true的元素。
    如,筛选出所有学生:

    1. List<Person> result = list.stream()
    2. .filter(Person::isStudent)
    3. .collect(toList());

    去重distinct

    去掉重复的结果:

    1. List<Person> result = list.stream()
    2. .distinct()
    3. .collect(toList());

    截取

    截取流的前N个元素:

    1. List<Person> result = list.stream()
    2. .limit(3)
    3. .collect(toList());

    跳过

    跳过流的前n个元素:

    1. List<Person> result = list.stream()
    2. .skip(3)
    3. .collect(toList());

    映射

    对流中的每个元素执行一个函数,使得元素转换成另一种类型输出。流会将每一个元素输送给map函数,并执行map中的Lambda表达式,最后将执行结果存入一个新的流中。
    如,获取每个人的姓名(实则是将Perosn类型转换成String类型)

    1. List<Person> result = list.stream()
    2. .map(Person::getName)
    3. .collect(toList());

    合并多个流

    例:列出List中各不相同的单词,List集合如下: ```java List list = new ArrayList();

list.add(“I am a boy”);

list.add(“I love the girl”);

list.add(“But the girl loves another girl”);

  1. 思路如下:<br />首先将list变成流:
  2. ```java
  3. list.stream();

按空格分词:

  1. list.stream()
  2. .map(line->line.split(" "));

分完词之后,每个元素变成了一个String[]数组。
将每个 String[] 变成流:

  1. list.stream()
  2. .map(line->line.split(" "))
  3. .map(Arrays::stream)

此时一个大流里面包含了一个个小流,我们需要将这些小流合并成一个流。
将小流合并成一个大流:用 flatMap 替换刚才的 map

  1. list.stream()
  2. .map(line->line.split(" "))
  3. .flatMap(Arrays::stream)

去重

  1. list.stream()
  2. .map(line->line.split(" "))
  3. .flatMap(Arrays::stream)
  4. .distinct()
  5. .collect(toList());

是否匹配任一元素:anyMatch

anyMatch用于判断流中是否存在至少一个元素满足指定的条件,这个判断条件通过Lambda表达式传递给 anyMatch,执行结果为boolean类型。
如,判断list中是否有学生:

  1. boolean result = list.stream()
  2. .anyMatch(Person::isStudent);

是否匹配所有元素:allMatch

allMatch用于判断流中的所有元素是否都满足指定条件,这个判断条件通过Lambda表达式传递给anyMatch,执行结果为boolean类型。
如,判断是否所有人都是学生:

  1. boolean result = list.stream()
  2. .allMatch(Person::isStudent);

是否未匹配所有元素:noneMatch

noneMatch与allMatch恰恰相反,它用于判断流中的所有元素是否都不满足指定条件:

  1. boolean result = list.stream()
  2. .noneMatch(Person::isStudent);

获取任一元素findAny

findAny能够从流中随便选一个元素出来,它返回一个Optional类型的元素。

  1. Optional<Person> person = list.stream().findAny();

获取第一个元素findFirst

  1. Optional<Person> person = list.stream().findFirst();

归约

归约是将集合中的所有元素经过指定运算,折叠成一个元素输出,如:求最值、平均数等,这些操作都是将一个集合的元素折叠成一个元素输出。

在流中,reduce函数能实现归约。

reduce函数接收两个参数:

  1. 初始值
  2. 进行归约操作的Lambda表达式

元素求和:自定义Lambda表达式实现求和
例:计算所有人的年龄总和

  1. int age = list.stream().reduce(0, (person1,person2)->person1.getAge()+person2.getAge());
  1. reduce的第一个参数表示初试值为0;
  2. reduce的第二个参数为需要进行的归约操作,它接收一个拥有两个参数的Lambda表达式,reduce会把流中的元素两两输给Lambda表达式,最后将计算出累加之和。

元素求和:使用Integer.sum函数求和
上面的方法中我们自己定义了Lambda表达式实现求和运算,如果当前流的元素为数值类型,那么可以使用Integer提供了sum函数代替自定义的Lambda表达式,如:

  1. int age = list.stream().reduce(0, Integer::sum);

Integer类还提供了min 、max 等一系列数值操作,当流中元素为数值类型时可以直接使用。

数值流的使用

采用reduce进行数值操作会涉及到基本数值类型和引用数值类型之间的装箱、拆箱操作,因此效率较低。
当流操作为纯数值操作时,使用数值流能获得较高的效率。
将普通流转换成数值流,StreamAPI提供了三种数值流:IntStream、DoubleStream、LongStream,也提供了将普通流转换成数值流的。
三种方法:mapToInt、mapToDouble、mapToLong。
如,将Person中的age转换成数值流:

  1. IntStream stream = list.stream().mapToInt(Person::getAge);
  2. Stream API (上)

数值计算
每种数值流都提供了数值计算函数,如max、min、sum等。如,找出最大的年龄:

  1. OptionalInt maxAge = list.stream()
  2. .mapToInt(Person::getAge)
  3. .max();

由于数值流可能为空,并且给空的数值流计算最大值是没有意义的,因此max函数返回OptionalInt,它是Optional的一个子类,能够判断流是否为空,并对流为空的情况作相应的处理。
此外,mapToInt、mapToDouble、mapToLong进行数值操作后的返回结果分别为:OptionalInt、OptionalDouble、OptionalLong

中间操作和收集操作

操作 类型 返回类型 使用的类型/函数式接口 函数描述符
filter 中间 Stream Predicate T -> boolean
distinct 中间 Stream
skip 中间 Stream long
map 中间 Stream Function T -> R
flatMap 中间 Stream Function T -> Stream
limit 中间 Stream long
sorted 中间 Stream Comparator (T, T) -> int
anyMatch 终端 boolean Predicate T -> boolean
noneMatch 终端 boolean Predicate T -> boolean
allMatch 终端 boolean Predicate T -> boolean
findAny 终端 Optional
findFirst 终端 Optional
forEach 终端 void Consumer T -> void
collect 终端 R Collector
reduce 终端 Optional BinaryOperator (T, T) -> T
count 终端 long