java8 stream流入门

      学习流之前建议先学习lambda表达式的应用。

1.流简介

    Stream的优点:声明性,可复合,可并行。这三个特性使得stream操作更简洁,更灵活,更高效。

    Stream的操作有两个特点:可以多个操作链接起来运行;内部迭代;

    集合和流的区别:集合包含目前的所有元素,你要什么就去集合里取。流是你要什么,然后去计算得到你需要的值。流是按照需求生成的。

    流只能遍历一次,用完之后就不存在了,只能重新创建流才能使用。例如:

 IntStream i = IntStream.of(1,2,3,4); i.forEach(System.out::println);<!--forEach输入Consumer--> i.forEach(System.out::println);<!--报错,stream has already been operated upon or closed-->

    Collection接口使用的迭代,比如for-each,叫做外部迭代。流则是内部迭代,你只要告诉它干什么就行了。外部迭代你可以看到每一次迭代,而内部迭代你看不到,流帮你做了。

2.流操作

    java.util.stream.Stream有许多操作,但是可以分为两类:一种为中间操作,一种为终端操作。

   中间操作就是操作后返回一个流,比如map,filter,limit等等,中间操作只有在终端操作时才执行。

   终端操作就是把流变为结果不是流的值,比如void,List,Integer等等。比如forEach,count,collect等等。

   使用流一般包含三个动作:生成流,中间操作,终端操作。

3.使用流

   3.1构建流

       由值生成流:

 IntStream i = IntStream.of(1,2,3,4); Stream<String> s = Stream.of("a","b","c"); Stream<String> emptyStream = Stream.empty();<!--创建一个空的流-->

       由数组创建流:

 int[] numbers = {1,2,3,4}; IntStream intStream = Arrays.stream(numbers);

      由文件生成流:
             java.nio.file.Files很多方法都会返回流。比如Files.lines会返回指定文件各行构成的字符串流

// hello // world // stream >>>data.txt数据 try(Stream<String> lines = Files.lines(Paths.get("D:\\Desktop\\data.txt"))){ long words =lines.flatMap(line->Arrays.stream(line.split(""))).distinct().count(); System.out.println(words); }catch(IOException e){ e.printStackTrace(); }

      由函数生成流:
             Stream Api有两个静态方法生成流:Stream.iterate,Stream.generate。这两个方法可以生成无限流,可以无限制的计算产生流数据。一定要加limit限制大小。

 Stream.iterate(0, x->x+1).limit(10).forEach(System.out::println); Stream.generate(()->2).limit(10).forEach(System.out::println);

      一般使用的是集合生成的流,Collection接口有默认方法产生流。只要实现Collection的类都可以用这个方法。

 List<Integer> list = Arrays.asList(1,2,3,4); list.stream().forEach(System.out::println);

   3.2筛选

           流的filter方法,参数为Predicate。返回满足Predicate的元素。也就是返回true的元素。

 List<Integer> list = Arrays.asList(1,2,3,4); list.stream().filter(i->i>=2).forEach(System.out::println);

            流的distinct方法返回各异的元素,返回的元素不能重复。

 List<Integer> list = Arrays.asList(1,2,3,4,2,3); list.stream().distinct().forEach(System.out::println);

            流的limit方法限制最多返回多少元素。

 List<Integer> list = Arrays.asList(1,2,3,4,2,3); list.stream().limit(2).forEach(System.out::println);

           流的skip方法不要前多n个元素,n大于满足条件的元素个数就返回空的流。

 List<Integer> list = Arrays.asList(1,2,3,4,2,3); list.stream().filter(i->i>=2).skip(2).forEach(System.out::println);

   3.3映射

        流的map方法作用于每个元素,并且返回一个新的元素,参数为Function。

 List<Integer> list = Arrays.asList(1,2,3,4,2,3); list.stream().filter(i->i>=2).map(a->"map"+a).forEach(System.out::println);

       map可以改变Stream的类型,上面就是把Stream<Integer>变为Stream<String>了。
       流的flatMap方法可以把各个数组映射的流合为一个流。例如得到文件字母的个数。

lines.flatMap(line->Arrays.stream(line.split(""))).distinct().count();

       如果直接用map(line->line.spilt(“”))得到的是很多个Stream<String[]>。
       如果用map(line->Arrays.stream(line.split(“”)))得到的是很多个Stream<String>。
       flatMap就是把很多个Stream<String>合为一个Stream<String>这样就可以算字母个数了。不然分为很多个流不能算字母个数。

   3.4查找与匹配

        anyMatch方法参数为Predicate。返回一个boolean值,表示流中是否有元素满足Predicate。

 List<Integer> list = Arrays.asList(1,2,3,4,2,3); boolean result = list.stream().anyMatch(i->i==2);

        allMatch方法与anyMatch差不多,表示所有的元素都满足才返回true。
noneMatch方法表示没有元素满足。
        这三个操作都是短路操作。短路操作就是不需要遍历所有的元素就能得到结果。就可&&和||操作符一样。limit方法就是一个短路操作。
         findAny方法,没有参数,表示返回随机的一个元素。返回一个Optional,因为有可能元素不存在。

 List<Integer> list = Arrays.asList(1,2,3,4,2,3); Optional<Integer> result = list.stream().findAny(); System.out.println(result.orElse(0));

        findFirst方法,没有参数,返回第一个元素。返回Optional。

   3.5归约

        流的reduce操作就是将流中的元素结合得到一个值。根据reduce方法中的操作,两两结合得到一个值,然后跟下一个元素结合,就这样一直到最后一个元素,得到最终的值。

 List<Integer> list = Arrays.asList(1,2,3,4,2,3); Optional<Integer> sum = list.stream().reduce(Integer::sum);<!--reduce可以指定初始值--> Optional<Integer> max = list.stream().reduce(Integer::max); Optional<Integer> min = list.stream().reduce(Integer::min);

        流还有max和min方法,参数为Comparator。

		List<Integer> list = Arrays.asList(1,2,3,4,2,3);
		Optional<Integer> max = list.stream().max(comparing(Integer::intValue));
		Optional<Integer> min = list.stream().min(comparing(Integer::intValue));

   3.6数值流

        上面讲的操作如Stream<Integer>会有装箱拆箱的操作。Stream中有IntStreamDoubleStream
LongStream分别表示流中的元素为int,double,long,这样可以避免装箱拆箱。

         mapToIntmapToDoublemapToLong着三个方法可以将Stream<T>转为数值流。数值流中有max,min,sum,average等方法。

		List<A> list = Arrays.asList(new A(1),new A(5),new A(3));
		int sum = list.stream().mapToInt(a->a.getNum()).sum();
		OptionalInt max = list.stream().mapToInt(a->a.getNum()).max();
		OptionalInt min = list.stream().mapToInt(a->a.getNum()).min();
		OptionalDouble ave = list.stream().mapToInt(a->a.getNum()).average();

        
boxed() 方法可以将数值流转为对象流。

		List<A> list = Arrays.asList(new A(1),new A(5),new A(3));
		Stream<Integer> i = list.stream().mapToInt(a->a.getNum()).boxed();

        
IntStream

LongStream
的静态方法,帮助生成这种范围:
range

rangeClosed
。这两个方法都是第一个参数接受起始值,第二个参数接受结束值。但
range
是不包含结束值的,而
rangeClosed
则包含结束值。

		IntStream.range(1, 100).filter(i->i%2==0).count();

    原文作者:逗比123号
    原文地址: https://blog.csdn.net/u014034934/article/details/76999007
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞