A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

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中有IntStream、 DoubleStream和
LongStream分别表示流中的元素为int,double,long,这样可以避免装箱拆箱。
         mapToInt、 mapToDouble和mapToLong着三个方法可以将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();

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马