Stream流
普通循环写法,迭代在外部进行
流式写法,迭代由内部控制,内部迭代将更多控制权交给了集合类
Stream
的使用非常类似建造者模式
Stream
中的方法通常分为以下两种:
-
惰性求值:不会进行方法执行,其特征:返回值为stream
-
及早求值:会触发方法执行
Stream
的常用方法
- forEach: 迭代
- map:用新的值替代Stream中的旧值,mapToInt则可以将Stream转化为IntStream
- flatMap: 把一个流中的每个值都换成另一个流,然后把所有的流连接
起来成为一个流(将流扁平化) - filter:过滤部分Stream中的值
- distinct: 去除重复元素
- limit:截取流中指定个数元素
- skip: 跳过流中指定个数的元素,和limit起到互补作用
- allMatch/anyMatch/noneMatch: 全部匹配/任意一个匹配/没有匹配,返回
boolean
- findAny/findFirst: 返回任意一个元素/返回第一个元素,返回类型为
Optional
- min&max: 求最大最小值
- count: 计算个数
- reduce: 递归操作
- peek:用于记录日志或查看每一个值
高阶函数:如果函数的参数列表里包含函数接口,或该函数返回一个函数接口,那么该函数就是高阶函数,例如map方法
数值流
数值流包含IntStream
、LongStream
、DoubleStream
,它们避免了隐形的拆箱成本,并且实现了一些独有的数值计算方法,如max
、min/max
、average
、range/ranged
、summaryStatistics
等,需要转换回对象流可以使用boxed
方法,或者mapToObj
方法
创建流的方式
- 由值创建:
Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
- 由数组创建:
int[] numbers = {2, 3, 5, 7, 11, 13}; int sum = Arrays.stream(numbers).sum();
- 由文件创建:
Stream<String> lines =
Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
- 由函数创建:
Stream.iterate(0, n -> n + 2).limit(10).forEach(System.out::println);
Stream.generate(Math::random).limit(5).forEach(System.out::println);
Optional
Optional<T>
是一个容器类,代表一个值存在或不存在,使用Optional<T>
定义属性的类型可以清楚说明属性是否支持为null
创建Optional对象
- 声明一个空的
Optional
Optional<Car> optCar = Optional.empty();
- 依据一个非空值创建
Optional
Optional<Car> optCar = Optional.of(car);
- 可接受null的
Optional
Optional<Car> optCar = Optional.ofNullable(car);
Optional无法序列化
Optional<T>
类型的属性无法序列化,实在需要用到的情况可以采用以下方式
public class Person {
private Car car;
public Optional<Car> getCarAsOptional() {
return Optional.ofNullable(car);
}
}
Optional的常用方法
- map/flatMap/filter:与
Stream
中用法类似 - get():值存在时返回值,否则抛出一个NoSuchElement异常
- isPresent():有值则返回true
- ifPresent(Consumer<T> block):会在值存在的时候执行给定的代码块
- orElse(T other):值存在时返回值,否则返回一个默认值
- orElseGet(Supplier<? extends T> other):orElse方法的延迟调用版,Supplier
方法只有在Optional对象不含值时才执行调用 - orElseThrow(Supplier<? extends X> exceptionSupplier):与get()类似,不同的是可以自定义异常类型
收集器工具类Collectors
可在Stream
的collect
方法中使用
-
toCollection
转换成其他集合 -
maxBy
/minBy
/averagingInt
/summingInt
转换成值 -
partitioningBy
数据二分 -
groupingBy
数据分多组 -
joining
字符串拼接(可支持自定义分隔符、前缀和后缀)
注:menu.stream().map(Dish::getName).collect(joining());
中当Dish
对象实现了toString
方法时,可以直接简写为menu.stream().collect(joining());
-
mapping
转换集合类型
并行化流
- parallel: 将流并行化
- sequential: 将流串行化
并行流底层使用了fork/join框架,因此能重复将数据结构对半分解的难易程度,决定了分解操作的快慢,如支持随机读取的数组并行化处理的性能最好,其次是TreeSet
、HashSet
这样不易公平分解的数据类型,最差的是LinkedList
这样长度未知的数据类型。
并行化数组操作
可以通过工具类Arrays
进行,其主要方法有
- copyOf 复制数组
- parallelSetAll 使用Lambda表达式更新数组元素
- parallelPrefix 任意给定一个函数,逐个将当前元素和之前的累计值进行函数操作
- parallelSort 并行化对数组元素进行排序
网友评论