Java 8:流

CSDN(https://blog.csdn.net/wisfy_21/article/details/80356822)要审核,现在看不了,先暂存一下。

[TOC]

流简介

流提供了对数据集合操作的简便方式,而且它更加灵活,性能也更好。与集合关注数据不同,流更加关注对数据的处理。

流的使用使得代码语义更加明确,易于阅读,比如:

//找到符合条件的数据并打印
Stream.of(23, 34, 124, 5, 19, 2, 4, 100)
        .filter(i -> i > 20 && i < 100)
        .forEach(System.out::println);

流的使用一般包含以下几个部分:

  1. 数据源,比如,集合、数组或者输入/输出资源。
  2. 中间操作。中间操作一般都会返回另一个流,而且中间操作不会立即执行。除非流水线上触发一个终端操作,否则中间操作不会执行任何处理。
  3. 终端操作。终端操作从流中得到处理结果,一般结果不是流。

需要注意的是,流只能消费一次。

流操作

流的重点在于对数据的处理。简单认识流之后,实际使用还需要明白流可以做哪些事情。下面列举几个常用的操作:

筛选、切片

1.filter,根据函数式接口Predicate的实例,操作的结果(boolean),返回包含所有符合要求的数据的流。
2.distinct,返回去重后的新的数据流。元素是否重复根据hashCode和equals方法判断。

Stream.of(23, 34, 124, 23, 19, 2, 4, 100)
        .filter(i -> i > 20 && i < 100)
        .distinct()
        .forEach(System.out::println);

3.limit,限制返回流中元素的个数。
4.skip,跳过指定个数的元素。

IntStream.range(0,100)
        .skip(50)
        .limit(5)
        .forEach(i -> System.out.print(i + " "));
//50 51 52 53 54 

查找、匹配

查找操作有两个:

  1. findFirst,返回当前流中的第一个元素
  2. findAny,返回当前流中的一个元素,不关心位置。这里并不会随机返回一个数据,单线程环境下还是一直返回第一个元素。但是在并行环境下,如果不关心返回数据的位置,findAny的性能更优。

注意:两者返回的数据都是Optional 结构的数据,它包含目标数据。当查找的数据不存在时,目标数据是null。它有几个常用的方法:

  1. isPresent(),是否包含值
  2. ifPresent(Consumer consumer),当值存在时,执行函数式接口Consumer,其接口签名为:void accept(T t);
  3. T get(),返回值,不存在是将抛出错误。
  4. T orElse(T other),如果值存在返回值,不存在返回指定的值作为默认值。
Stream.of("A", "B","D","P","M","S","Q")
        .filter(str -> str.compareTo("H") > 0)
        .findAny()
        .ifPresent(System.out::println);
//输出:P

匹配操作有allMatch、anyMatch、noneMatch。匹配操作返判断流中的数据是否满足指定条件,它们的返回值是boolean类型。

boolean result = Stream.of("A", "B","D","P","M","S","Q")
        .allMatch(str -> str.compareTo("a") < 0);

规约

规约指reduce操作,将数据流中的数据进行规约操作,得到一个值。通过reduce操作可以很方便的实现求和、最大与最小值得计算等等。

求和:

int sum = IntStream.range(0,101).reduce((a,b) -> a+ b).getAsInt();
System.out.println(sum);

最大值:

int max = new Random()
        .ints(0,1000)
        .limit(100)
        .reduce(Integer::max).getAsInt();

注:reduce操作有三个版本,使用时可以根据需要选择。

映射

  • map操作,将每一个元素映射为另一个元素。
Stream.iterate(0, i -> i+2).limit(10).map(i -> i*2).forEach(System.out::println);

map应该是个很强大的操作,比如可以从对象中提取指定的属性,或者对对象执行某些操作得到新的对象等等。

  • flatMap操作,合并流的内容,扁平化为一个流
List result = Stream.of("Hello","night")
        .map(w -> w.split("")) //返回的是Stream
        .flatMap(Arrays::stream) //将每个String[]转成Stream,合并
        .distinct()
        .collect(toList());
System.out.println(result);
//[H, e, l, o, n, i, g, h, t]

收集

collect操作是一个终端操作,可以将根据指定操作转成集合或者Map。

流的构建

  • 使用Stream.of通过值来构建
  • 通过数组来构建
int[] numbers = {2,354,56,6,76,31,12};
int max = Arrays.stream(numbers).max().getAsInt();
System.out.println(max);
  • 集合构建,Collection接口的stream方法可以直接放回流
List numbers = Arrays.asList(2,354,56,6,76,31,12);
int min = numbers.stream().min(Integer::compareTo).get();
System.out.println(min);
  • 文件生成流
Files.lines(Paths.get("F:\\data.txt")).forEach(System.out::println);
  • 无限流
    使用Stream.iterate和Stream.generate方法,可以按需产生无线流。
Stream.iterate(0, i -> i+2).limit(100).forEach(System.out::println);

Stream.generate(Math::random).limit(10).forEach(System.out::println);

数值流

Stream流中的数据都是对象类型,如果希望操作数据的话,使用时暗含装箱操作。为避免这个问题,Java 8提供了IntStream、DoubleStream、LongStream。这些流类型不仅仅是在内部使用基本类型,还提供了数值操作的快捷API,像sum、max、min等等。而且,它们与Stream之间可以相互转化。

注:内容主要来自《Java 8实战》,目前只介绍了简单的用法,更多的像分组分区、自定义收集器等,后面找机会再补补。

你可能感兴趣的:(Java 8:流)