手记

Java 8 数据流Stream的使用

一.Java里面对Stream的定义:

A sequence of elements supporting sequential and parallel aggregate operations.

支持顺序和集合并行操作的一系列元素。

(1)Stream是元素的集合,类似于Iterator,单向,不可往复,数据只能遍历一次,遍历过一次数据即用尽了

(2)Stream 可以并行化操作,迭代器只能命令式地、串行化操作;

(3)Stream 的另外一大特点是,数据源本身可以是无限的。

二.创建Stream

1.通过Stream接口的静态工厂方法:

(1)of方法;

  (2)   generate方法;

(3)iterate方法;

import java.util.function.Supplier;
import java.util.stream.Stream;
public class NewStream {  
  public static void main(String[] args) {       
        //第一种  of方法;
        int shuzu[] = {4, 5, 6, 7, 8};
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
        integerStream.forEach(System.out::println);
        Stream<String> stringStream = Stream.of("taobao", "weixin", "baidu", "toutiao");
        stringStream.forEach(System.out::println);
        Stream.of(shuzu).forEach(System.out::println);        //第二种  generate方法
        Stream.generate(new Supplier<Double>() {            @Override
            public Double get() {                return Math.random();
            }
        }).limit(10).forEach(System.out::println);        //第三种  iterate方法
        Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println);

    }
}

2.通过collection的子类来获取Stream(Collection接口有一个Stream方法,所以其所有子类都可以获取对应的Stream对象。)

        List list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.stream().forEach(System.out::println);
        LinkedList linkedList = new LinkedList();
        linkedList.add(6);
        linkedList.add(7);
        linkedList.add(8);
        linkedList.add(9);
        linkedList.add(10);        //并行流
        linkedList.parallelStream().forEach(System.out::println);
        Set hashSet = new HashSet();
        hashSet.add(11);
        hashSet.add(12);
        hashSet.stream().forEach(System.out::println);

三 .Stream操作

操作类型

接口方法


Intermediate

(中间操作)

无状态(Stateless)map(mapToInt、mapToLong、flatmap、mapToDouble、 flatMapToInt、flatMapToLong、flatMapToDouble)、unordered、filter、 peek、 parallel 、sequential  、isParallel
有状态(Stateful)distinct、 sorted、limit、 skip

Terminal

(最终操作)

非短路操作forEach、forEachOrdered、 toArray、 reduce、collect、 max、min、count、

Short-circuiting

(短路操作)

anyMatch、allMatch、noneMatch、findFirst、 findAny

中间操作和结束操作:

中间操作只是一种标记,结束操作才会触发实际计算;

中间操作后可以跟随其他操作,可以进行多次中间操作,结束操作执行后Stream元素就被消费掉了,无法对一个Stream进行两次terminal操作。

中间操作又可以分为无状态的(Stateless)和有状态的(Stateful),无状态的中间操作是指元素的处理不受前面元素的影响,而有状态的中间操作必须等到所有元素处理之后才知道最终结果,比如排序是有状态操作,在读取所有元素之前并不能确定排序结果,filter是无状态操作,符合过滤条件就被选出来,不关注其他元素的状态;

结束操作又可以分为短路操作和非短路操作,短路操作是指不用处理全部元素就可以返回结果,比如找到第一个满足条件的元素

1.map()和flatMap()使用

map():将提供的函数应用于流的元素的结果

flatmap():将提供的流处理函数应用于流元素后获得的流元素


2.filter()使用

filter():根据传入的表达式,筛选出符合条件的元素

 //   过滤不为null的元素    结果1 2 3 4 5 6 7 8 9
        Stream.of(1, 2, 3, 4, 5, null, 6, null, 7, null, 8, 9).
                filter(integerStreams -> integerStreams != null).forEach(System.out::println);

3.unordered()使用

4.forEach()和peek()使用

forEach()和peek()方法都可以接收一个Lambda表达式,然后在Stream的每个元素上执行该表达式。

不同的是:

forEach是terminal操作。peek是一个intermediate操作,可以多次操作Stream。

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ForeachAndPeek {  
  public static void main(String[] args) {

        Stream a = Stream.of("one", "two", "three", "four");        /*
         * forEach对于流来说是terminal操作,a第一次forEach后,就被"消费"掉了,所以第二次forEach就会报错
         */
        a.forEach(System.out::println);        //a.forEach(System.out::println);
        //Stream.of("one", "two", "three", "four").forEach(System.out::println).forEach(System.out::println);

        //这是两个不同的流去执行forEach操作,所以不会报错
        Stream.of("one", "two", "three", "four").forEach(System.out::println);
        Stream.of("one", "two", "three", "four").forEach(p -> System.out.println(p));        /*
         * peek操作不是terminal操作,而是intermediate操作。所以可以多次操作Stream
         */
        Stream b = Stream.of("one", "two", "three", "four");        /*
         * Stream b已经被操作或者被消费掉了,已经没有Stream b了,会报错。
         * 报错信息:stream has already been operated upon or closed
         */
        //b.peek(System.out::println);
        //可以用一个新的Stream接收,再操作新的Stream
        Stream c = b.peek(System.out::println).peek(p -> System.out.println(p));
        c.peek(System.out::println);        /*
         * peek操作的用法
         */
        List streamList = Stream.of("one", "two", "three", "four").
                filter(e -> e.length() > 3).peek(e -> System.out.println("Filtered value: " + e)).
                map(String::toUpperCase).
                peek(e -> System.out.println("Mapped value: " + e)).collect(Collectors.toList());
        System.out.println(streamList);
    }
}

5.sequential()和parallel()和isParallel()的使用:

sequential()是将并行流转化称串行流。parallel是将串行流转化成并行流。

isParallel判断是否为并行执行,输出结果为true和false。

        List<Integer> list = new ArrayList<>();    
            for (int i=1;i<=10;i++){
            list.add(i);
        }
        list.stream().parallel().forEach(a->System.out.print(a+","));
        System.out.println();
        list.parallelStream().sequential().forEach(a->System.out.print(a+","));
        System.out.println();
        System.out.println("===================");
        System.out.println(list.stream().isParallel());
        System.out.println(list.parallelStream().isParallel());
        System.out.println(list.stream().parallel().isParallel());
        System.out.println(list.parallelStream().sequential().isParallel());

输出结果为:


可以看出来,.parallel()输出的结果为乱序,.sequential() 方法输出的结果为顺序输出。

6.distinct()和count()使用

distinct():去重操作,输出结果为已经删除了重复元素的流元素;

count():返回流的元素个数;

public class distinct {   
 public static void main(String[] args) {
        List list = new ArrayList();
        list.add(1);
        list.add("2");
        list.add(3L);
        list.add(1L);
        list.add(4L);
        list.add(3L);
        list.stream().forEach((a)-> System.out.print(a+ " "));
        System.out.println( "count:"+list.stream().count());
        list.stream().distinct().forEach((a)-> System.out.print(a+ " "));
        System.out.println( "count:"+list.stream().distinct().count());
    }
}

输出结果如下:

7.sorted()使用

sorted():将数据按自然顺序进行排序。

sorted(Comparator<T>):将数据按提供的比较符进行排序。


8.limit()和skip()的使用

limit(long) 返回 Stream 的前面long个元素;

skip(long)丢弃了Stream的前面long个元素;

public class SkipAndLimit {    
public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(5);
        list.add(6);
        list.add(3);
        list.add(4);
        list.add(7);
        list.add(8);
        list.add(9);
        list.add(6);
        list.add(3);
        list.add(4);
        list.stream().limit(3).forEach(System.out::print);
        System.out.println();
        System.out.println("~~~~~~~");
        list.stream().skip(3).forEach(System.out::print);
    }
}

输出结果集如下:


9.forEach()和forEachOrdered()使用

  forEach是并行处理的;

  forEachOrdered是按顺序处理的。

  所以forEach效率会略高一点。

package Stream;
import java.util.Arrays;
import java.util.List;
public class ForEachAndForEachOrdered {  
  public static void main(String[] args) {
        List<String> list = Arrays.asList("Two","Three","One","Four","Five");
        list.stream().forEach(p->System.out.print(p+" "));
        System.out.println("。");
        list.stream().forEachOrdered(p->System.out.print(p+" "));
        System.out.println("。");        //每次打印输出顺序是不一致的。
        list.parallelStream().forEach(p->System.out.print(p+" "));
        System.out.println("。");
        list.parallelStream().forEachOrdered(p->System.out.print(p+" "));
        System.out.println("。");
    }
}

10.toArray()使用

11.reduce()使用

reduce:将流的元素聚合为一个汇总值。

public class Reduce {   
 public static void main(String[] args) {   
      // 字符串连接,concat = "ABCD"
        String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
        System.out.println(concat);       
         // 求最小值,minValue = -3.0
        double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
        System.out.println(minValue);     
           // 求和,sumValue = 1009, 有起始值(起始值+Sum(-1+1+2+3+4))
        int sumValue = Stream.of(-1, 1, 2, 3, 4).reduce(1000, Integer::sum);
        System.out.println(sumValue);     
           // 求和,sumValue = 10, 无起始值
        sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
        System.out.println(sumValue);      
          // 过滤,字符串连接,concat = "BDF"
        concat = Stream.of("a", "B", "c", "D", "e", "F").filter(x -> x.compareTo("Z") < 0).reduce("", String::concat);
        System.out.println(concat);
    }
}

12.collect()使用

collect():将流的元素聚合到一个汇总结果容器中。

List<Integer> list  = Stream.of(1,2,3,4,5,6,7,8,9).collect(Collectors.toList());

13.max()和min()使用

max()返回流中最大的值;

min()返回流中最小的值;

这几种方式都是可以的:

package Stream;
import java.util.Comparator;
import java.util.stream.Stream;public class MaxAndMin {  
  public static void main(String[] args) {     
        int a = Stream.of(-99, -100, 3, 5, 9, 99).max(Integer::compare).get();//99
        int b = Stream.of(-99, -100, 3, 5, 9, 99).min(Integer::compare).get();//-100
        int c = Stream.of(-99, -100, 3, 5, 9, 99).max((n, m) -> Integer.compare(n, m)).get();//99
        int d = Stream.of(-99, -100, 3, 5, 9, 99).min((n, m) -> Integer.compare(n, m)).get();//-100
        int e = Stream.of(-99, -100, 3, 5, 9, 99).max(Comparator.comparing(Integer::valueOf)).get();//99
        int f = Stream.of(-99, -100, 3, 5, 9, 99).min(Comparator.comparing(Integer::valueOf)).get();//-100
        int j = Stream.of(-99, -100, 3, 5, 9, 99).mapToInt(i -> i).max().getAsInt();//99
        int l = Stream.of(-99, -100, 3, 5, 9, 99).mapToInt(i -> i).min().getAsInt();//-100
        System.out.println("a:"+a);
        System.out.println("b:"+b);
        System.out.println("c:"+c);
        System.out.println("d:"+d);
        System.out.println("e:"+e);
        System.out.println("f:"+f);
        System.out.println("j:"+j);
        System.out.println("l:"+l);
    }
}

输出结果如下:


还有一种经典的错误demo,这种方式是不可行的:

因为stream().max()是以返回值的正数,负数和0来判断大小的

 public static void main(String[] args) {        //错误的用法
        int g = Stream.of(-99,-100,3,5,9,99).max(Integer::max).get();        int h = Stream.of(-99,-100,3,5,9,99).min((v,k) -> {            int result = Integer.max(v, k);            return result;
        }).get();
        System.out.println("g:"+g);
        System.out.println("h:"+h);

    }

14.allMatch(),anyMatch()和noneMatch()的使用

allMatch:Stream中全部元素符合传入的条件返回true;

anyMatch:Stream中有一个元素符合传入的条件就返回true;

noneMatch:Stream中没有一个元素符合传入的条件返回true;

        List<Integer> list = new ArrayList<>();   
             for (int i=1;i<=10;i++){
            list.add(i);
        }
        list.stream().forEach(System.out::println);
        System.out.println("全部大于9:"+list.stream().allMatch(a->a>9));
        System.out.println("全部大于0:"+list.stream().allMatch(a->a>0));
        System.out.println("有一个及以上大于9:"+list.stream().anyMatch(a->a>9));
        System.out.println("有一个及以上大于10:"+list.stream().anyMatch(a->a>10));
        System.out.println("没有一个大于9:"+list.stream().noneMatch(a->a>9));
        System.out.println("没有一个大于10:"+list.stream().noneMatch(a->a>10));

输出结果为:


15.findFirst()和findAny()的使用

findFirst()返回第一个元素,如果流为空,则返回一个空Optional。

findAny()返回任意一个元素,如果流为空,则返回一个空Optional。对于并行流来说可能多次返回结果不一致,但是性能会略优秀于findFirst()。

public class FindFirstAndDFindAny {   
 public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();     
           for (int i = 1; i <= 10000; i++) {
            list.add(i);
        }
        System.out.println(list.parallelStream().findAny());
        System.out.println(list.parallelStream().findAny());
        System.out.println(list.parallelStream().findAny());
        System.out.println(list.parallelStream().findAny());
        System.out.println(list.parallelStream().findAny());
        System.out.println(list.parallelStream().findAny());
        System.out.println(list.parallelStream().findAny());
        System.out.println(list.parallelStream().findAny());
        System.out.println(list.parallelStream().findFirst());
        System.out.println(list2.parallelStream().findFirst());
    }
}

结果如下:

可以看出多次执行并行流的findAny操作,结果是不一样的。


1人推荐
随时随地看视频
慕课网APP