2018-08-16使用流Stream

一、引入流

  • 为了利用多核架构并行执行这段代码,你只需要把stream()换成parallelStream():
  • 因为filter、sorted、map和collect等操作是与具体线程模型无关的高层次构件,所以
    它们的内部实现可以是单线程的,也可能透明地充分利用你的多核架构!在实践中,这意味着你用不着为了让某些数据处理任务并行而去操心线程和锁了,Stream API都替你做好了!
List collect = apples.parallelStream()
                .filter(d -> d.getWeight() > 150)
                .sorted(Comparator.comparing(Apple::getWeight).reversed())
                .map(Apple::getColor)
                .collect(Collectors.toList());
2018-08-16使用流Stream_第1张图片
中间操作.png

小结

  • 流是“从支持数据处理操作的源生成的一系列元素”
  • 流利用内部迭代:迭代通过filter、map、sorted等操作被抽象掉了
  • 流操作有两类:中间操作和终端操作。
  • filter和map等中间操作会返回一个流,并可以链接在一起。可以用它们来设置一条流水线,但并不会生成任何结果
  • forEach和count等终端操作会返回一个非流的值,并处理流水线以返回结果。
  • 流中的元素是按需计算的

二、使用流

筛选和切片

1.用谓词筛选
  • Streams接口支持filter方法。该操作会接受一个谓词(一个返回boolean的函数)作为参数,并返回一个包括所有符合谓词的元素的流。
2.筛选各异的元素
  • 流还支持一个叫作distinct的方法,它会返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流。
3.截短流
  • 流支持limit(n)方法,该方法会返回一个不超过给定长度的流。所需的长度作为参数传递给limit。如果流是有序的,则最多会返回前n个元素。
4.跳过元素
  • 流还支持skip(n)方法,返回一个扔掉了前n个元素的流。如果流中元素不足n个,则返回一个空流。请注意,limit(n)和skip(n)是互补的!

流的扁平化

flatmap方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接

给定两个数字列表,如何返回所有的数对呢?例如,给定列表[1, 2, 3]和列表[3, 4],应该返回[(1, 3), (1, 4), (2, 3), (2, 4), (3, 3), (3, 4)]。为简单起见,你可以用有两个元素的数组来代表数对。

List numbers1 = Arrays.asList(1, 2, 3);
List numbers2 = Arrays.asList(3, 4);
List pairs = numbers1.stream()
        .flatMap(i -> numbers2.stream().map(j -> new int[]{i, j}))
        .collect(toList());

查找和匹配

  • Stream API通过allMatch、anyMatch、noneMatch、findFirst和findAny方法来处理
    数据集中的某些元素是否匹配一个给定的属性
1.检查谓词是否至少匹配一个元素
  • anyMatch方法可以回答“流中是否有一个元素能匹配给定的谓词”。anyMatch方法返
    回一个boolean,因此是一个终端操作。
if(menu.stream().anyMatch(Dish::isVegetarian)){
    System.out.println("The menu is (somewhat) vegetarian friendly!!");
}
2.检查谓词是否匹配所有元素
  • allMatch方法的工作原理和anyMatch类似,但它会看看流中的元素是否都能匹配给定的谓词。
boolean isHealthy = menu.stream() allMatch(d -> d.getCalories() < 1000); 
  • noneMatch, 和allMatch相对的是noneMatch。它可以确保流中没有任何元素与给定的谓词匹配。
3.查找元素
  • findAny方法将返回当前流中的任意元素。它可以与其他流操作结合使用。
 Optional dish =  menu.stream() .filter(Dish::isVegetarian) .findAny() ;

Optional类(java.util.Optional)是一个容器类,代表一个值存在或不存在。在 上面的代码中,findAny可能什么元素都没找到。

4.查找第一个元素
  • findFirst 方法,它的工作方式类似于findany。
    下面的代码能找出第一个平方能被3整除的数:
List someNumbers = Arrays.asList(1, 2, 3, 4, 5);
Optional firstSquareDivisibleByThree = someNumbers.stream()
        .map(x -> x * x)
        .filter(x -> x % 3 == 0)
        .findFirst(); // 9 

归约

  • 此类查询需要将流中所有元素反复结合起来,得到一个值,比如一个Integer。这样的查询可以被归类为归约操作(将流归约成一个值)。
1.元素求和
int sum = numbers.stream().reduce(0, (a, b) -> a + b); 

reduce接受两个参数:
1.一个初始值,这里是0;
2.一个BinaryOperator来将两个元素结合起来产生一个新值,这里我们用的是
lambda (a, b) -> a + b。
Lambda反复结合每个元素,直到流被归约成一个值。

在Java 8中,Integer类现在有了一个静态的sum方法来对两个数求和,这恰好是我们想要的,用不着反复用Lambda写同一段代码了:

int sum = numbers.stream().reduce(0, Integer::sum); 
2.最大值和最小值
Optional max = numbers.stream().reduce(Integer::max); 
Optional min = numbers.stream().reduce(Integer::min); 
2018-08-16使用流Stream_第2张图片
中间操作和终端操作.png

小结

  • 你可以使用filter、distinct、skip和limit对流做筛选和切片。
  • 你可以使用map和flatMap提取或转换流中的元素。
  • 你可以使用findFirst和 findAny方法查找流中的元素。你可以用allMatch、
    noneMatch和anyMatch方法让流匹配给定的谓词。
  • 这些方法都利用了短路:找到结果就立即停止计算;没有必要处理整个流。
  • 你可以利用reduce方法将流中所有的元素迭代合并成一个结果,例如求和或查找最大元素
  • filter和map等操作是无状态的,它们并不存储任何状态。reduce等操作要存储状态才能计算出一个值。sorted和distinct等操作也要存储状态,因为它们需要把流中的所有元素缓存起来才能返回一个新的流。这种操作称为有状态操作。
  • 流有三种基本的原始类型特化:IntStream、DoubleStream和LongStream。它们的操作也有相应的特化。
  • 流不仅可以从集合创建,也可从值、数组、文件以及iterate与generate等特定方法创建。
  • 无限流是没有固定大小的流。

你可能感兴趣的:(2018-08-16使用流Stream)