Java8之流(Stream)操作与可空类(Optional)

​Java8的集合支持新的stream方法会返回流(java.util.stream.Stream),流只能遍历一次;其可以支持常用的类似数据库的流操作。中间操作可以连接起来(将一个流转换为另一个流)构建一个流水线,终端操作会消耗流,以产生一个最终结果:

  • 中间操作(返回Stream)

    • filter(Predicate):返回匹配的流;

    • map(Function):映射,返回应用map后的流;

    • limit(long maxSize):返回不超过maxSize数量元素的流;

    • sorted(Comparator):排序;

    • disctinct():去重;

    • skip(n):跳过n个元素;

    • flatMap(Function>):流扁平化,把多个流合并为一个流;

  • 数值映射:

    • 映射到数值流:mapToInt, mapToDouble, mapToLong,特化后避免调用时装箱拆箱处理;

    • 转回对象流:boxed,如把int转回为Integer

  • 终端操作(只有调用终端时,所有流操作才真正执行):

    • void forEach(Consumer):对每个元素执行Consumer;

    • long count():返回元素数;

    • collect(Collector):返回集合,如collect(Collectoor.toList());

    • 元素操作(返回Optional):ifPrecent()可以在Optional有值时执行

      • findAny():返回某个元素;

      • findFirst():返回第一个元素,流为空时返回空;

      • max(Comparator):返回最大元素;

      • min(Comparator):返回最小元素;

    • 匹配操作:

      • allMatch:全部匹配;

      • anyMatch:任一匹配;

      • noneMatch:无匹配;

    • 归约操作:

      • T reduce(T init, BinaryOperator accumulatro):对每个元素归约,如求和reduce(0, Integer::sum),

 

收集器Collectors类中的静态方法:

  • toList

  • toSet:生成set(删除重复项)

  • toCollection:指定集合,如collect(toCollection(), ArrayList::new);

  • counting:计算元素的个数,collect(counting());

  • summingInt:求和

  • averagingInt:求平均数;

  • summarizingInt:获取统计值(最大、最小、总和、平均值等);

  • joining:对流中每个元素的调用toString后连接成字符串,如collect(joining(", "));

  • maxBy, minBy

  • reducing:归约操作;

  • collectingAndThen:包裹另一个收集器,并对结果应用转换函数,如collect(collectingAndThen(toList(), List::size));

  • groupingBy:分组

  • partitioningBy:分区(分成true与false两组);

 

获取菜单(集合)中3条菜肴名称,并连接为一个字符串

String names = menu.stream()

.map(Dish::getName)

.limit(3)

.collect(Collectors.joining("; "));

 

获取包含的字符(去重后字符列表)

words = ["Hello", "World"]

words.stream()

.map(wd -> wd.split(""))

.flatMap(Arrays::stream)

.disctinct()

.collect(Collectors.toList());

 

构建流:

生成数值流:IntStream, LongStream,IntStream.rangeClosed(1, 100):[1,100]间数字组成的流;

Strean.of(...):显示构建流;

Arrays.Stream:由数组构建流;

由文件构建流:Files中很多静态方法会返回流;

由函数构建流:Stream.iterate, Stream.generate;

IntSupplier fib = new IntSupplier(){

int pre = 0;

int cur = 1;

public int getAsInt(){

int old = pre;

int next = pre+cur;

pre = cur;

cur = next;

return old;

}

}

IntStream.generate(fib).limit(10).forEach(System.out::println);

 

并行数据处理

要并行处理数据,可以通过对源调用parallelStream方法把集合转换为并行流,或调用parallel()方法把顺序流转换为并行流(sequential在转换为顺序流):

stream.parallel().

    .filter(...)

    .sequential()

    .map(...)

    .parallel()

    .reduce()

 

要高效处理数据,需要:

  • 留意装箱:自动装箱与拆箱会大大降低性能;Java8中的(IntStream, LongStream, DoubleStream)可避免此操作,尽量使用之;

  • 有些操作在并行流上就是比顺序流上性能差:特别是limit、findFirst等依赖元素顺序的。

  • 要考虑流的操作流水线的总计算成本;

  • 对于较小的数据量,并行几乎从来都不是一个好的决定;

  • 考虑流背后的数据结构是否易于分解:如ArrayList比LinkedList易于拆分;数据源与可分解性:

    • ArrayList:极佳;

    • LinkedList:差;

    • IntStream.range:极佳;

    • Stream.iterate:差;

    • HashSet:好;

    • TreeSet:好;

 

Optional

Java8中引入java.util.Optional用于存在或缺失变量的建模;可以明确表明可否为空(不存在)。

创建Optional对象:

  • Optional.empty():声明空的Optional;

  • Optional.of(inst):非空(包含对应值的),若inst为null,则抛出NullPointerException;

  • Optional.ofNullable(inst):创建允许null值的,若inst为null,则创建空的;

从Optional中读取实例的变量值:

  • get():存在则返回变量值,否则抛出NoSuchElementException异常;

  • orElse(T other):存在则返回变量值,否则返回默认值(other);

  • orElseGet(Supplier other):orElse延迟调用版,只有在对象不存在时,才会调用Supplier(可能是耗时操作);

  • orElseThrow(Supplier exceptionSupplier):与get类似,但是抛出指定的异常;

  • ifPresent(Consumer):存在则返回变量值,否则无任何操作;

其他类方法:

  • filter:值存在且满足过滤条件则返回包含值的Optional对象,否则返回空Optional;

  • flatMap:若值存在执行提供的mapping函数,返回一个Optional类型的值,否则返回空Optional;

  • map:若值存在执行提供的mapping函数;

  • isPresent:值存在返回true,否则返回false;

 

多个Optional的链式操作(getCar返回Optional,getName直接返回String),通过flatMap避免Optional的嵌套(Optional>):

Optional person=...;

String name = person.filter(p -> p.getAge() > 20)

        .flatMap(Person::getCar)

        .map(Car::getName)

        .orElse("Unkown");

你可能感兴趣的:(Java)