java8-Stream API(1)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/answer100answer/article/details/87899299

概述

了解stream

Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API(java.util.stream.*)
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之, Stream API 提供了一种高效且易于使用的处理数据的方式。

流(Stream): 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
这里的Stream和IO中的Stream不同,它提供了对集合操作的增强,极大的提高了操作集合对象的便利性。
“集合讲的是数据,流讲的是计算!”

特点

  • Stream 自己不会存储元素;
  • Stream 不会改变源对象; 相反,它们会返回一个持有结果的新Stream;
  • Stream 操作是延迟执行的; 这意味着它们会等到需要结果的时候,才执行;

Stream 操作的三个步骤

  • 创建 Stream
    一个数据源(如: 集合,数组),获取一个流;
    如:可以通过 Collection 集合提供的串行流 stream()并行流 parallelStream()
  • 中间操作
    一个中间操作链,对数据源的数据进行处理;
  • 终止操作(终端操作)
    一个终止操作,执行中间操作链,并产生结果;

1.创建stream

1.Collection 扩展接口,提供了两个获取流的方法

  • default Stream<E> stream() : 返回一个顺序流
  • default Stream<E> parallelStream() : 返回一个并行流

2.由数组创建流
Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:

  • static <T> Stream<T> stream(T[] array): 返回一个流

重载形式,能够处理对应基本类型的数组:

  • public static IntStream stream(int[] array)
  • public static LongStream stream(long[] array)
  • public static DoubleStream stream(double[] array)

3.由Stream静态方法创建

  1. 由值创建流 Stream.of()
    可以使用静态方法 Stream.of(), 通过显示值 创建一个流。它可以接收任意数量的参数。
    public static<T> Stream<T> of(T... values) : 返回一个流
  2. 由函数创建流:无限流 Stream.iterate()Stream.generate()
    – 迭代:public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
    – 生成:public static<T> Stream<T> generate(Supplier<T> s)
	@Test
    public void test1(){
        //1通过Collection系列集合提供的stream()或 paralleStream()
        List<String> list = new ArrayList<>();
        Stream stream1 = list.stream();
        Stream stream2 = list.parallelStream();

        //2.通过Arrays中的静态方法stream()
        Employee[] employees = new Employee[8];
        Stream<Employee> stream3 = Arrays.stream(employees);

        //3.通过Stream类的静态放of()、iterate()、generate()创建
        //of
        Stream<String> stream4 = Stream.of("a","b","c");
        //无限流1:iterate
        Stream<Integer> stream5=Stream.iterate(0,x->x+2);
        stream5.limit(5).forEach(x->System.out.print(x)); //02468
        //无限流2:generate
        Stream<Integer> stream6 = Stream.generate(()->(int)(Math.random()*100));
        stream6.limit(6).forEach(x-> System.out.print(x)); 
    }

2.中间操作

筛选与切片

  • filter 接收lambda,从流中排除某些元素
  • limit 截断流,使其元素不穿过给定数量。limit在filter后一起使用可以短路
  • skip(n) 跳过元素,返回一个丢掉前n个元素的流,若流不足n个,返回一个空流,与limit互补
  • distinct 去重,通过元素的hashCode() 和 equals()比较去重

映射

  • map 接收lambda 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成为一个新的元素
  • flatMap 接收一个函数为参数,将流中的每个值换成另一个流,然后把所有的流连接成一个流

排序

扫描二维码关注公众号,回复: 5723779 查看本文章
  • sorted() 自然排序
  • sorted(Compator com) 定制排序

filter

	/**
     * filter
     * 内部迭代:迭代操作由StreamAPI完成
     */
    @Test
    public void test1(){
        //中间操作 不会执行任何操作
        List<Employee> employees = Lists.newArrayList(new Employee(12, 1000), new Employee(20, 2000));
        Stream<Employee> stream = employees.stream()
                .filter((e) -> {
                    System.out.println("中间操作");
                    return e.getAge() > 13;
                });
        //终止操作 一次性执行全部内容,即“惰性求值”
        stream.forEach(System.out::println); //Employee(age=20, salary=2000)
    }

limit

    /**
     * 截断流 一旦找到满足条件的数据,后续的迭代结束
     */
    @Test
    public void test3(){
        List<Employee> employees = Lists.newArrayList(new Employee(12, 1000), new Employee(20, 2000));
        employees.stream()
                .filter((e)->{
                    System.out.println("短路!");
                    return e.getSalary()>60;
                })
                .limit(1)
                .forEach(System.out::println);
    }
    //短路!
	//Employee(age=12, salary=1000)

skip

    /**
     * 跳过
     */
    @Test
    public void test4(){
        List<Employee> employees = Lists.newArrayList(new Employee(12, 1000), new Employee(20, 2000));
        employees.stream()
                .filter(e->e.getSalary()>60)
                .skip(1)
                .forEach(System.out::println);
        //Employee(age=20, salary=2000)
    }

distinct

    /**
     * 去重 重写hashCode和equals
     */
    @Test
    public void test5(){
        List<String> ss = Lists.newArrayList("a","a","b","c","c");
        ss.stream().distinct()
                .forEach(System.out::print);//abc
    }

map和flapMap

二者区别 https://blog.csdn.net/andyzhaojianhui/article/details/79047825
类似addaddAll的关系。add参数是集合每个元素,返回至集合。addAll参数是整个集合,实际操作是加入的集合中每个元素,返回至集合。

map
map的返回结果:取决于map中的函数返回类型,返回结果是什么就是什么,再加上外层的Stream

    //map
    @Test
    public void test6(){
        /**
         * map
         */
        List<String> list = Arrays.asList("a","b","c");
        System.out.println(list); //[a, b, c]
        //将list中的每个元素转换成数字
        Stream<Integer> stream = list.stream().map(s->{
            Integer i;
            switch (s){
                case "a":i=1;break;
                case "b":i=2;break;
                case "c":i=3;break;
                default:i=0;
            }
            return i;
        });
        stream.forEach(System.out::print); //123
    }

flatMap在取深层元素时很有用。
flatMap的返回结果中,两层Sream包裹的仅保留一层Stream,并去掉集合的一层。
作用1:【输入】将输入去掉一层集合后返回 借助u->u.stream()

    //map与flatMap对比
    @Test
    public void test7(){
        /**
         * flatMap
         */
        List<String> l1= Arrays.asList("a","b","c");
        System.out.println(l1);//[a, b]
        List<String> l2= Arrays.asList("x","y");
        System.out.println(l2);//[x, y]

        //map
        Stream<List<String>> s =Stream.of(l1,l2);
        //map的返回结果:取决于map中的函数返回类型,返回结果是什么就是什么,再加上外层的Stream
        Stream<List> s1 = s.map(li -> Lists.newArrayList(li,"1"));
        s1.forEach(System.out::println); //[[a, b, c], 1][[x, y], 1]

        //flatMap
        Stream<List<String>> ss =Stream.of(l1,l2);
        //flatMap作用1:将输入去掉一层后返回
        Stream<String> s2 = ss.flatMap(u->u.stream());
        s2.forEach(System.out::print);

        //测试多层Stream和List的情况:仅保留一层Stream并去掉集合的一层
        List<List<String>> lists = Lists.newArrayList();
        List<String> ls1=Lists.newArrayList("didi");
        List<String> ls2=Lists.newArrayList("hi","my");
        lists.add(ls1);
        lists.add(ls2);
        System.out.println(lists); //[[didi], [hi, my]]
        Stream<List<List<String>>> si = Stream.of(lists);
        Stream<List<String>> s3 = si.flatMap(u->u.stream());
        s3.forEach(System.out::print); //[didi][hi, my]  由此可见仅去掉了一层
    }

作用2:【输出】flatMap中的函数返回,如果也是Stream,则仅保留一层stream

    // flatMap的返回结果测试
    public  Stream<Character> characterStream(String s) {
        List<Character> result = new ArrayList<>();
        for (char c : s.toCharArray())
            result.add(c);
        return result.stream();  //list转stream,一个级别上
    }
    @Test
    public void test8(){
        List<String> words = new ArrayList<String>();
        words.add("your");
        words.add("name");
        Stream<Stream<Character>> result1 = words.stream().map(this::characterStream);
        //测试map
        result1.forEach(System.out::println);//打印的是两个Stream对象
        //java.util.stream.ReferencePipeline$Head@12bb4df8
        //java.util.stream.ReferencePipeline$Head@4cc77c2e
        Stream<Character> result2 = words.stream().flatMap(this::characterStream);
        //测试flatMap
        result2.forEach(System.out::println); //一个个的字符
    }

flatmap示例2:

    @Test
    public void testMapAndFlatMap() {
        List<String> words = new ArrayList<String>();
        words.add("hello");
        words.add("word");

        //将words数组中的元素再按照字符拆分,然后字符去重,最终达到["h", "e", "l", "o", "w", "r", "d"]
        //如果使用map,是达不到直接转化成List<String>的结果
        List<String> stringList = words.stream()
                .flatMap(word -> Arrays.stream(word.split("")))
                .distinct()
                .collect(Collectors.toList());
        stringList.forEach(e -> System.out.println(e));
    }

sorted() 自然排序(Comparable)
sorted(Compator com) 定制排序 (Comparator)

     List<String> list = Arrays.asList("bbb","zzz","yyy","ccc","sss");

     list.stream()
         .sorted()
         .forEach(System.out::println);

    // 员工排序
    employees.stream()
             .sorted((e1,e2) -> {
                if(e1.getAge().equals(e2.getAge())){
                    return e1.getName().compareTo(e2.getNme());
                }else{
                    return e1.getAge().compareTo(e2.getAge());
                }
             }).forEach(System.out::println);

3.终止操作

终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:ListInteger,甚至是 void

查找与匹配

  • 查找与匹配
  • allMatch 检查是否匹配所有元素
  • anyMacth 检查是否至少匹配一个元素
  • noneMacth 检查是否没有匹配所有元素
  • findFirst 返回第一个元素
  • findAny 返回任意一个元素
  • count 返回元素总数
  • max 返回最大值
  • min 返回最小值
  • forEach 内部迭代(使用 Collection 接口需要用户去做迭 代,称为外部迭代。相反,Stream API 使用内部 迭代——它帮你把迭代做了)

归约

  • reduce(T identity,BinaryOperator) 可以将流中元素反复结合起来,得到一个值。 返回 T
  • reduce(BinaryOperator) 可以将流中元素反复结合起来,得到一个值。 返回 Optional

收集

  • collect(Collector c) 将流转换为其他形式。接收一个 Collector接口的 实现,用于给Stream中元素做汇总的方法

备注:map 和 reduce 的连接通常称为 map-reduce 模式,因 Google 用它 来进行网络搜索而出名

查找匹配demo

    @Test
    public void test1(){
        boolean b1 = studentList.stream()
                .allMatch((e) -> e.getStatus() == Student.Status.FREE);
        System.out.println(b1);
 
        boolean b2 = studentList.stream()
                .anyMatch((e) -> e.getStatus() == Student.Status.FREE);
        System.out.println(b2);
 
        boolean b3 = studentList.stream()
                .noneMatch((e) -> e.getStatus() == Student.Status.FREE);
        System.out.println(b3);
 
        Optional<Student> op1 = studentList.stream()
                .sorted((e1, e2) -> -Integer.compare(e1.getScore(), e2.getScore()))
                .findFirst();
        System.out.println(op1.get());
 
        Optional<Student> op2 = studentList.stream()
                .filter((e) -> e.getStatus() == Student.Status.FREE)
                .findAny();
        System.out.println(op2.get());
        //并行流
        Optional<Student> op3 = studentList.parallelStream()
                .filter((e) -> e.getStatus() == Student.Status.FREE)
                .findAny();
        System.out.println(op3.get());
        //count
        long count = studentList.stream()
                .count();
        System.out.println(count);
        //max
        Optional<Student> max = studentList.stream()
                .max(Comparator.comparing(Student::getName));
        System.out.println(max.get());
        //min
        Optional<Integer> min = studentList.stream()
                .map(e -> e.getScore())
                .min(Integer::compare);
        System.out.println(min.get());
 
    }

reduce

    //reduce
    @Test
    public void test9(){
        /*
         * 归约
         *   reduce(T identity, BinaryOperator) / reduce(BinaryOperator)
         *     可以将流中元素反复结合起来,得到一个值; 其中 第一个参数identity,表示起始值
         */
        // 需求: 将list集合中的元素相加
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer sum = list.stream()
                .reduce(0,(x,y) -> x+y);
        System.out.println(sum); //55

        List<Employee> employees = Lists.newArrayList(new Employee(12, 1000), new Employee(20, 2000));
        // 获取员工工资的总和
        Optional<Integer> op = employees.stream()
                .map(Employee::getSalary)
                .reduce(Integer::sum);
        System.out.println(op.get()); //3000
    }

collect
Collector 接口中方法的实现决定了如何对流执行收集操作(如收 集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态 方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

    //collect
    @Test
    public void test10(){
        /*
         * 收集
         *   collect: 将流转换为其他形式,接收一个Collector 接口的实现,用于给 Stream 中元素做汇总的方法
         *          Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List, Set, Map)
         *          Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例;
         */
        List<Employee> employees = Lists.newArrayList(new Employee(12, 1000), new Employee(20, 2000));

        // 需求: 将员工中年龄收集到 list 集合
        List<Integer> list = employees.stream()
                .map(Employee::getAge)
                                 .collect(Collectors.toList());
        list.forEach(System.out::println);

        // 将员工姓名收集到 HashSet 中
        HashSet<Integer> hset = employees.stream()
                .map(Employee::getAge)
                .collect(Collectors.toCollection(HashSet::new)); //toSet()
        // 员工总人数
        Long count = employees.stream()
                .collect(Collectors.counting());
        System.out.println("总数"+count);

        // 工资平均值
        Double avg = employees.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println("平均"+avg);

        // 工资总和
        Double sum = employees.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println("综合"+sum);

        // 按照Status进行分组
//        Map<Status, List<Employee>> map = employees.stream()
//                .collect(Collectors.groupingBy(Employee::getStatus));
//        System.out.println(map);

        // 分区(满足条件的一个区,不满足条件的在另一个区)
        Map<Boolean, List<Employee>> map = employees.stream()
                .collect(Collectors.partitioningBy((e) -> e.getSalary() > 1700));
        System.out.println(map); //{false=[Employee(age=12, salary=1000)], true=[Employee(age=20, salary=2000)]}

        DoubleSummaryStatistics dss = employees.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));

        System.out.println(dss.getSum());
        System.out.println(dss.getAverage());
        System.out.println(dss.getMax());

        // 连接字符串
//        String str = employees.stream()
//                .map(Employee::getName)
//                .collect(Collectors.joining(","));
//        System.out.println(str);
    }

其他demo。参考 https://blog.csdn.net/keepstrong/article/details/80154295
分组

 /**
     * 分组
     */
    @Test
    public void test5(){
        Map<Student.Status, List<Student>> map = studentList.stream()
                .collect(Collectors.groupingBy(Student::getStatus));
        System.out.println(map);
    }
    @Test
    public void test6(){
        Map<Student.Status, Map<String, List<Student>>> map = studentList.stream()
                .collect(Collectors.groupingBy(Student::getStatus, Collectors.groupingBy((e) -> {
                    if (e.getAge() < 15) {
                        return "小朋友";
                    } else {
                        return "青年";
                    }
                })));
        System.out.println(map);
    }

分区

 @Test
    public void test7(){
        Map<Boolean, List<Student>> map = studentList.stream()
                .collect(Collectors.partitioningBy((e) -> e.getScore() > 70));
        System.out.println(map);
    }

统计

   @Test
    public void test8(){
        IntSummaryStatistics iss = studentList.stream()
                .collect(Collectors.summarizingInt(Student::getScore));
        System.out.println(iss.getSum());
        System.out.println(iss.getAverage());
        System.out.println(iss.getCount());
        System.out.println(iss.getMax());
    }

拼接

    @Test
    public void test9(){
        String str = studentList.stream()
                .map(Student::getName)
                .collect(Collectors.joining(","));
        System.out.println(str);
    }







猜你喜欢

转载自blog.csdn.net/answer100answer/article/details/87899299