java8流操作

2019-06-20  本文已影响0人  请叫我铁臂阿童木

流是Java API的新成员,它允许你以声明性方式处理数据集合

流操作有两个重要的特点:

  1. 流水线——很多流操作本身会返回一个流,这样多个操作就可以链接起来,形成一个大的流水线。

2.内部迭代——与使用迭代器显式迭代的集合不同,流的迭代操作是在背后进行的。

流与集合的区别:

集合中的每个元素都得先算出来才能添加到集合中

流就像是一个延迟创建的集合,只有在消费者要求的时候才会计算值

流的构建

Stream.of("Java 8 ", "Lambdas ", "In ", "Action") 由值创建流

Arrays.stream(numbers) 由数组创建流

List.stream() 集合创建流

Stream API提供了两个静态方法来从函数生成流:Stream.iterate和Stream.generate。 这两个操作可以创建所谓的无限流:不像从固定集合创建的流那样有固定大小的流。由iterate 和generate产生的流会用给定的函数按需创建值,因此可以无穷无尽地计算下去!一般来说, 应该使用limit(n)来对这种流加以限制,以避免打印无穷多个值。

流的使用

可以使用流进行筛选&切片、映射、查找&匹配、归约。

下列使用均以此List为例

List<Dish> menu = Arrays.asList(
                new Dish("pork", false, 800, Dish.Type.MEAT),
                new Dish("beef", false, 700, Dish.Type.MEAT),
                new Dish("chicken", false, 400, Dish.Type.MEAT),
                new Dish("french fries", true, 530, Dish.Type.OTHER),
                new Dish("rice", true, 350, Dish.Type.OTHER),
                new Dish("season fruit", true, 120, Dish.Type.OTHER),
                new Dish("pizza", true, 550, Dish.Type.OTHER),
                new Dish("prawns", false, 300, Dish.Type.FISH),
                new Dish("salmon", false, 450, Dish.Type.FISH));

流收集器

我们在之前提到了collect,其作用是规约,将流中的元素使用Collector累积成一个汇总结果。

Collectors.counting()汇总数量

Collectors.maxBy() 获取最大值

例:

// 获取菜单列表中卡路里数值最大的菜。
Comparator<Dish> dishCaloriesComparator=Comparator.comparingInt(Dish::getCalories);
Optional<Dish> mostCalorieDish = menu.stream().collect(maxBy(dishCaloriesComparator));

Collectors.summingLong和Collectors.summingDouble 这两个方法用于求和,可以用于求和字段为long或double的情况。

Collectors.averagingInt(),连同对应的averagingLong和 averagingDouble 用于计算数值的平均数

万能方法:Collectors.summarizing(),可以获取元素个数,总和,平均值、最大值、最小值。

Collectors.joining() 内部使用了StringBuilder来把生成的字符串逐个追加起来.

Collectors.reducing() 接受一个BinaryOperator<t>参数,也就是一个 BiFunction<T,T,T>。这就意味着它需要的函数必须能接受两个参数,然后返回一个相同类型的值。


Collectors.groupingBy() 分组

// 根据卡路里进行分组,返回一个Map<CaloricLevel, List<Dish>> 类型的结果
public enum CaloricLevel { DIET, NORMAL, FAT }
Map<CaloricLevel, List<Dish>> dishesByCaloricLevel 
= menu.stream().collect( groupingBy(dish -> { 
               if (dish.getCalories() <= 400) return CaloricLevel.DIET;
               else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                        else return CaloricLevel.FAT;
                        }));
// 多级分组,根据类型分组,再统计数量,返回结果Map: {MEAT=3, FISH=2, OTHER=4}
Map<Dish.Type,Map<CaloricLevel,List<Dish>>> map = menu.stream()
  .collect(Collectors.groupingBy(Dish::getType,Collectors.groupingBy((Dish d)->{
            if (d.getCalories()<400){return CaloricLevel.DIET;}
                    else {return CaloricLevel.FAT;}
            })));
/**
普通的单参数groupingBy(f)(其中f是分类函数)实际上是groupingBy(f, toList())的简便写法。
*/

Collectors.partitioningBy() 分区

// 区分出素食与非素食
menu.stream().collect(partitioningBy(Dish::isVegetarian))

并行流

<u>并行流就是一个把内容分成多个数据块,并用不同的线程分别处理每个数据块的流。这样一来,你就可以自动把给定操作的工作负荷分配给多核处理器的所有内核。</u>

Stream.parallel() 顺序流转为并行流

Stream.sequential () 并行流转为顺序流

在使用并行流时,要避免共享可变状态,确保并行Stream得到正确的结果。

并行流内部使用了默认的ForkJoinPool ,它默认的 线程数量就是你的处理器数量 ,可 以 通 过 系 统 属 性 java.util.concurrent.ForkJoinPool.common. parallelism来改变线程池大小 ,System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism","12");

上一篇 下一篇

猜你喜欢

热点阅读