java Stream类详解(附代码演示)

文章目录

  • 引言
    • 流和集合的区别:
    • stream的工作流:
  • 创建Stream
  • 转换
    • filter()过滤
    • map()映射
    • flatMap()平铺映射。流中元素个数可能会增加。
  • 扩展和拼接streams
    • limit()限制返回的个数
    • skip()跳过开始的个数
    • concat()拼接两个stream
  • 其他转换方式
    • distinct()去重
    • sorted()排序
  • 收集结果
    • forEach()遍历流
    • peek() 对每个元素执行操作并返回一个新的 Stream
    • toArray()将stream存储为array
    • collect
    • Match
    • grouping,partitioning
    • Reductions
  • 原始类型stream

引言

Streams遵循"what,no how"原则。

流和集合的区别:

  1. 流不存储元素。他们可以被存储在隐式的集合中或者按命令生成。
  2. 流操作不改变源。
  3. 流操作是懒惰型的,他们只有在实际调用到的时候才会执行。

学习Stream的前提是掌握Lambda表达式!

stream的工作流:

  1. 创建stream
  2. 采用详尽的中间操作将初始的stream转换为另一个stream,即相当于链式调用
  3. 采用终止的操作产生一个结果,此后stream不再使用
  int sum = widgets.stream()
                      .filter(w -> w.getColor() == RED)
                      .mapToInt(w -> w.getWeight())
                      .sum();

stream()创建流;filter,mapToInt()转换;sum()终止。

创建Stream

流的创建主要有以下几种:

  1. Collection的实现类例如List,Set,Queue等调用stream()方法:
    Stream<String> colle = new ArrayList<String>().stream();
  1. 数组类型调用Arrays.stream()方法/可变参数类型调用Stream.of()方法:
    int[] ints = {1, 2, 3};
    Arrays.stream(ints);
    Arrays.stream(ints, 1, 2);//可以指定生成的起始和终点
    Stream.of(1, 2, 3);
  1. 创建一个空的流:
    Stream<String> silence = Stream.empty();
  1. 从文件读取一个流:
    Path path = Paths.get("D:\\hhh\\test.xml");
    Files.lines(path).forEach(System.out::println);
  1. 无限流,用Stream.generate方法和Stream.iterate方法:
    //常量Stream
    Stream<String> echos = Stream.generate(() -> "Echo");
    //随机数Stream
    Stream<Double> randoms = Stream.generate(Math::random);
    Stream.iterate(new Integer(1), (x)-> x+1).forEach(System.out::println);

转换

filter(),map(),flatMap()

filter()过滤

例如筛选字符串长度,通常流中的元素个数会减少。

    List<String> list = Arrays.asList("a", "ab", "ba", "c");
    list.stream()
        .filter((x)-> x.length() > 1)
        .forEach(System.out::println);
        

输出:

ab
ba

map()映射

例如大小写转换。流中元素个数不变。

    List<String> list = Arrays.asList("a", "ab", "ba", "c");
    list.stream()
        .map(w -> w.toUpperCase())
        .forEach(System.out::println);

输出:

A
AB
BA
C

flatMap()平铺映射。流中元素个数可能会增加。

    public static void main(String[] args) {
        List<String> list = Arrays.asList("a", "ab", "ba", "c");
        list.stream()
            .flatMap(w -> letters(w))
            .forEach(System.out::println);
    }

    /**
     * 将字符串s分割成由单个字符组成的List,再通过stream方法转成流。
     * @param s
     * @return
     */
    public static Stream<String> letters(String s) {
        List<String> result = new ArrayList<>();
        for (int i = 0; i < s.length(); i++) {
            result.add(s.substring(i, i + 1));
        }
        return result.stream();
    }

输出:

a
a
b
b
a
c

扩展和拼接streams

limit()限制返回的个数

    List<String> list = Arrays.asList("a", "ab", "ba", "c");
    list.stream()
            .limit(2L)
            .forEach(System.out::println);

输出:

a
ab

skip()跳过开始的个数

    List<String> list = Arrays.asList("a", "ab", "ba", "c");
    list.stream()
            .skip(2L)
            .forEach(System.out::println);

输出:

ba
c

concat()拼接两个stream

    List<String> list = Arrays.asList("a", "ab", "ba", "c");
    List<String> list1 = Arrays.asList("1", "2", "3", "4");
    Stream.concat(list.stream(), list1.stream()).forEach(System.out::println);

输出:

a
ab
ba
c
1
2
3
4

其他转换方式

distinct()去重

    List<String> list = Arrays.asList("a", "a", "ab", "ba", "c");
    list.stream()
            .distinct()
            .forEach(System.out::println);

输出

a
ab
ba
c

sorted()排序

sorted有两个实现方法,一个是无参的 一个是有参的。
Stream sorted()。
Stream sorted(Comparator comparator)。

    List<String> list = Arrays.asList("a", "a", "ab", "ba", "c");
    list.stream()
            .forEach(w -> System.out.print(w + " "));
    System.out.println();
    list.stream()
        .sorted(Comparator.comparing(w -> w.length()))
        .forEach(w -> System.out.print(w + " "));

输出

a a ab ba c 
a a c ab ba 

收集结果

forEach()遍历流

peek() 对每个元素执行操作并返回一个新的 Stream

通常收集结果会消费掉流,但是使用peek不会消费掉流,而被视为一个中间操作。

    List<String> list = Arrays.asList("a", "a", "ab", "ba", "c");
    list.stream()
            .peek(x -> System.out.println("peek:" + x))
            .filter(x -> x.length() > 1)
            .forEach(System.out::println);

输出:

peek:a
peek:a
peek:ab
ab
peek:ba
ba
peek:c

toArray()将stream存储为array

无参的toArray方法直接返回Object[]对象。

而 A[] toArray(IntFunction generator),返回对应的类型。例如toArray(String[]::new)返回String[].

    List<String> list = Arrays.asList("a", "a", "ab", "ba", "c");
    String[] strings = list.stream()
            .filter(x -> x.length() > 1)
            .toArray(String[]::new);
    System.out.println(Arrays.toString(strings));//[ab, ba]

collect

  • collect(Collectors.toList()):list类型
  • collect(Collectors.toSet()):set类型
  • collect(Collectors.toCollection(TreeSet::new));TreeSet类型
  • collect(Collectors.joining())将stream中所有的string拼接成一条
  • collect(Collectors.joining(","))以,为分隔符拼接
    List<String> list = Arrays.asList("a", "a", "ab", "ba", "c");
    List<String> strings = list.stream()
            .filter(x -> x.length() > 1)
            .collect(Collectors.toList());
    System.out.println(strings); //[ab, ba]

    Set<String> set = list.stream()
            .filter(x -> x.length() > 0)
            .collect(Collectors.toSet());
    System.out.println(set);//[a, ab, c, ba]
    
    
    List<String> list = Arrays.asList("a", "a", "ab", "ba", "c");
    String s = list.stream()
        .filter(x -> x.length() > 0)
        .collect(Collectors.joining("+"));
    System.out.println(s);//a+a+ab+ba+c

IntSummaryStatistics collect(Collectors.summarizingInt(String::length)):将stream转为可计算的数字类型

  • getMax()
  • getAverage()
  • getCount()
  • getMin()
  • getSum()
    List<String> list = Arrays.asList("a", "a", "ab", "ba", "c");
    IntSummaryStatistics collect = list.stream()
            .filter(x -> x.length() > 0)
            .collect(Collectors.summarizingInt(String::length));
    System.out.println(collect.getMax()); // 2

Match

Stream 有三个 match 方法,从语义上说:

  • allMatch:Stream 中全部元素符合传入的 predicate,返回 true
  • anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true
  • noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
    List<String> list = Arrays.asList("a", "a", "ab", "ba", "c");
    boolean noneMatch = list.stream().noneMatch("c"::equals);
    boolean allMatch = list.stream().allMatch("c"::equals);
    boolean anyMatch = list.stream().anyMatch("c"::equals);
    System.out.println("noneMatch(没有任何一个匹配):" + noneMatch + "\nallMatch(所有都匹配):"+allMatch +"\nanyMatch(有一个匹配):"+anyMatch);

输出:

noneMatch(没有任何一个匹配):false
allMatch(所有都匹配):false
anyMatch(有一个匹配):true

修改输入为:

    List<String> list = Arrays.asList("a", "a");
    boolean noneMatch = list.stream().noneMatch("c"::equals);
    boolean allMatch = list.stream().allMatch("a"::equals);
    boolean anyMatch = list.stream().anyMatch("a"::equals);
        System.out.println("noneMatch(没有任何一个匹配):" + noneMatch + "\nallMatch(所有都匹配):"+allMatch +"\nanyMatch(有一个匹配):"+anyMatch);

输出:

noneMatch(没有任何一个匹配):true
allMatch(所有都匹配):true
anyMatch(有一个匹配):true

grouping,partitioning

这个讲解的话引入一个People类比较好讲,详见文章:

https://blog.csdn.net/sayWhat_sayHello/article/details/90199440

Reductions

reduce方法需要先了解java8中新增的Optional类型和lambda中的函数式接口BinaryOperator,理解了这两个之后才能比较好的去使用。

BinaryOperator代表接受两个T类型的参数,然后返回一个T类型的值:

    List<String> list = Arrays.asList("a", "a", "ab", "ba", "c");
    System.out.println(list.stream().reduce((x, y) -> x + y).orElse("hhh"));

reduce操作后返回Optional,由于结果不为空所以不会返回"hhh",而是输出:

aaabbac

相当于一直迭代: “a”+“a” = “aa”, “aa”+“ab” =“aaab” ……

原始类型stream

IntStream,LongStream,DoubleStream和对象stream的差异:

  1. toArray返回原始类型数组
  2. 返回的是OptionalInt,OptionalLong,OptionalDouble而不是Option,相应的get变为getAsInt,getAsLong,getAsDouble
  3. 定义了sum,average,max,min方法
  4. summaryStatistics调用返回的对应为IntSummaryStatistics,LongSummaryStatistics,DoubleSummaryStatistics

你可能感兴趣的:(java)