欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java8 Stream API

程序员文章站 2022-05-28 11:36:49
...

一. Stream API 概述

jva8在java.util.stream包下,通过Stream真正的引入函数式编程,可以对数据进行复杂的查找,过滤映射,提供了高效且易于使用的处理数据的方式,例如想要获取集合中的某些特定元素,在以前需要遍历集合,对每个元素进行筛选代码比较多,通过Stream,一行代码就可以搞定

  1. Stream 不会存储元素
  2. Stream 不会改变源对象,会返回一个持有结果的心的Stream
  3. Stream 是延迟执行的(创建一个有数据的Stream元数据流–>通过Stream对数据进行处理–>终止操作产生结果,只有调用终止操作以后前面的计算才会执行,否则算调用计算的方法,不执行的,终止后的Stream不可以再次继续进行中间处理,若想处理重新获取流,或一次性执行中间处理完毕后再调用终止)

二. Stream实例化方式

  1. 通过集合调用stream()方法获取Stream顺序流
  2. 通过集合调用parallelStream()方法获取Stream并行流
  3. 通过数组获取Stream
  4. 无限流

创建Stream流的方式代码示例

 	@Test
    public void test1(){
        //创建Stream的方式

        List<Persion> persionList = new ArrayList<>();

        persionList.add(new Persion("小明",22,2000.00));
        persionList.add(new Persion("小红",34,2500.00));
        persionList.add(new Persion("AA",18,1800.00));
        persionList.add(new Persion("小强",40,3500.00));
        persionList.add(new Persion("小黑",22,2200.00));
        persionList.add(new Persion("小花",27,2000.00));
        persionList.add(new Persion("bb",16,1500.00));

        //1.通过集合中的.stream()获取Stream流,注意该方法返回的是一个顺序流(根据向集合中添加的顺序)
        Stream<Persion> stream1 = persionList.stream();

        //通过集合中的parallelStream()获取一个并行流,有点像通过几个线程同时去取,顺序可能发生改变
        Stream<Persion> stream2 = persionList.parallelStream();

        //2.通过Arrays工具类中的stream(T[] array)静态方法获取Stream流
		//集合转数组
        Persion[] perArray =  persionList.toArray(new Persion[persionList.size()]);

        Stream<Persion> stream = Arrays.stream(perArray);
        //注意点,在使用Arrays中的stream()方法获取Stream流时,根据像方法中传递的
        //泛型T不同,其返回的Stream不同
        int[] iArray = new int[]{1,4,9};
        long[] lArray = new long[]{11l,22l,6l};
        double[] dArray = new double[]{7.8,14.3,5.1};
        IntStream intStream = Arrays.stream(iArray);
        LongStream longStream = Arrays.stream(lArray);
        DoubleStream doubleStream = Arrays.stream(dArray);

        //3.通过Stream的of()方法创建,将数据传入of()方法中
        Stream<Integer> stream3 = Stream.of(1, 2, 3, 4);

        //4.创建无限Stream流,输出0-10的偶数,
        //iterate()中0代表开始位置,后面的Lambda传递的是Function<T,T> +2返回
        //limit为中止操作,10
        //forEach()为执行体
        Stream.iterate(0,t -> t +2).limit(10).forEach(System.out :: println);

        //生成,获取10个随机数
        Stream.generate(Math :: random).limit(10).forEach(System.out :: println);
    }

三. Stream 中间操作(通过Stream操作数据)

概述

使用Stream对数据继续操作,例如过滤筛选,映射,排序等,注意点: Stream被称为"惰性求值",在进行中间操作时,如果最终不调用终止,则中间操作无效,在调用终止操作后,若有后续的操作需要重新获取Stream流,否则无效

1. 筛选切片

1)方法概述
java8 Stream API
2)代码示例

	@Test
    public void test1(){
		//persionList是一个List<Persion>集合
        //获取Stream流
        Stream<Persion> stream = persionList.stream();
        //筛选与切片
        //1.filter(Predicate p) 过滤,接收 Lambda ,从流中排除某些元素
        //获取集合中age大于20的数据
        stream.filter(p -> p.getAge()>20).forEach(System.out :: println);
       
        //2.limit(n) 截断流,使其元素不超过给定的数量n
        Stream<Persion> stream2 = persionList.stream();
        //获取集合中前三条数据
        stream2.limit(3).forEach(System.out :: println);
        
        //3.skip(n) 跳过元素,返回一个不包括n以前个数的元素,若流中不足n个数据则返回就返回一个空流
        //去掉集合中前3个元素
        persionList.stream().skip(3).forEach(System.out :: println);
        
        //4.distinct() 筛选,通过流所生成元素的hashCode()和equals()去除重复元素
        //去重
        persionList.stream().distinct().forEach(System.out :: println);
    }

2. 映射

1)方法概述
java8 Stream API
2)代码示例

	@Test
    public void test2(){

        //1.map(Function f) 接收一个函数作为参数,将元素映射成其它形式或获取信息,
        //该函数会被应用到每个元素上,并将其映射到新的元素
        //map()会依次对Stream中的每个元素执行
        //示例1,将集合中所有字符串转换为大写
        List<String> stringList = Arrays.asList("aa", "bb", "cc");
        stringList.stream().map(str -> str.toUpperCase()).forEach(System.out :: println);

        //示例2,获取集合姓名包含"小"的员工的姓名
        Stream<String> ageStream = persionList.stream().map(Persion::getName);
        ageStream.filter(name -> name.contains("小")).forEach(System.out :: println);

        //2.flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流
        //然后把所有流连接成一个流,与map()方法的区别有点像集合中的add(),与addAll()
        //假设调用add方法向集合中添加另外一个集合是会变成[obj1, obj2, obj3,List[obj1,obj2,obj3]]
        //如果调用addAll(),则会重新组合为一个集合,而不是集合作为集合类型元素存在
        //假设通过map()获取的数据是Stream<Stream<T>>,此时如果想要继续过滤就有点麻烦,可以通过flatMap()
        //例如调用下面自定义的fromStringToStream(String str)方法,返回多个Stream流,

        Stream<Stream<Character>> streamStream = stringList.stream().map(ArrayTest::fromStringToStream);
        //输出stringList中的所有char字符,由于调用ArrayTest类中中的fromStringToStream()方法
        //返回的是Stream<Stream<Charcter>>,需要两层farEach()
        streamStream.forEach(s -> {
            s.forEach(System.out :: println);
        });
        //使用flamtMap,则会将多个Stream流重新组合为一个
        Stream<Character> characterStream = stringList.stream().flatMap(ArrayTest::fromStringToStream);
        characterStream.forEach(System.out :: println);
    }

    //将String字符串,转换为char集合,并将char集合转换为Stream流返回
    public static Stream<Character> fromStringToStream(String str){
        ArrayList<Character> list = new ArrayList<>();
        for(Character c : str.toCharArray()){
            list.add(c);
        }
        return list.stream();
    }

3. 排序

1)方法概述
java8 Stream API

2)代码示例

	@Test
    public void test3(){
        //排序
        //1.sorted() 自然排序
        List<Integer> integers = Arrays.asList(12, 34, 20, 70, 60);
        integers.stream().sorted().forEach(System.out::println);

        //如果想要自定义类对象实现自然排序,该类需要实现Comparator接口,制定排序规则否则报错
        //否则使用sorted定制排序
        //2.sorted(Comparator com) 定制排序(如果年龄相等则使用工资排序)
        persionList.stream().sorted((p1, p2) ->{
            int ageVal = Integer.compare(p1.getAge(),p2.getAge());
            if(ageVal != 0){
                return ageVal;
            }else {
                return Double.compare(p1.getSalary(), p2.getSalary());
            }
        }).forEach(System.out :: println);
    }

四. Stream 的终止操作

终止操作,生成流的执行结果

1. 查找与匹配

1)方法概述
java8 Stream API
java8 Stream API
2) 代码示例

	@Test
	public void test4() {

        List<Persion> persionList = new ArrayList<>();
        persionList.add(new Persion("小明", 22, 2000.00));
        //add()......

        //一下的操作中都可以在加入中间操作实现过滤后再进行终止

        //1.allMatch(Predicate p) 检查元素是否匹配,所有都是true,才是true
        //判断是否集合中的所有年龄都大于18岁
        Boolean b1 = persionList.stream().allMatch(p -> p.getAge() > 18);

        //2.anyMatch(Predicate p) 检查是否有一个元素匹配,有一个为true则为true
        //判断集合中是否有工资大于5000
        Boolean b2 = persionList.stream().anyMatch(p -> p.getSalary() > 5000);

        //3.noneMatch(Predicate p) 检查是否没有匹配的
        //判断集合中是否有叫小明的,如果有则返回false
        boolean b3 = persionList.stream().noneMatch(p -> p.getName().contains("小明"));

        //4.findFirst 返回第一个元素,Option<>
        Optional<Persion> persionOptional = persionList.stream().findFirst();

        //5.findAny 返回当前流中任意元素
        Optional<Persion> anyPersion = persionList.stream().findFirst();

        //6.count 返回当前流中元素个数
        //获取工资超过2000的个数
        long count = persionList.stream().filter(p -> p.getSalary()>2000.00).count();

        //7.max(Comparator c) 返回当前流中最大的元素
        //返回最大工资的
        Optional<Persion> max = persionList.stream().max((p1, p2) -> Double.compare(p1.getSalary(), p2.getSalary()));

        //min(Comparator c) 返回最小的元素
        //返回年龄最小的
        Optional<Persion> min = persionList.stream().min((p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()));
        //返回最小年龄
        persionList.stream().map(p -> p.getAge()).min(Integer :: compare);

        //8.forEach(Consumer c) 内部迭代
        persionList.stream().forEach(System.out :: println);
    }

2. 规约

1)方法概述
java8 Stream API
2)代码示例

	@Test
    public void test5(){
        //1.reduce(T identity, BinaryOperator) 将六种的元素结合起来得到一个值并返回
        //查看BinaryOperator源码进行分析
        //BinaryOperator继承BiFunction<T,T,T>接口,该接口传递两个T类型参数,返回一个T类型参数
        //刚好符合Integer与Dubbo中的sum方法
        //计算1-10的自然数的和
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer reduce = list.stream().reduce(0, Integer::sum);
        //普通方式
        Integer reduce2 = list.stream().reduce(0, (i1, i2) -> i1 + i2);

        //2.reduce(BinaryOperator)
        //获取集合中工资总和
        List<Persion> persionList = new ArrayList<>();
        persionList.add(new Persion("小明", 22, 2000.00));
        //add()...

        Optional<Double> reduce1 = persionList.stream().map(Persion::getSalary).reduce(Double::sum);
        //普通方式
        persionList.stream().map(Persion::getSalary).reduce((d1, d2) -> d1+d2);
    }

3. 收集

1)方法概述
java8 Stream API
StreamAPI 收集 Collectors,将过滤终止的Stream结果数据收集为其他类型,与Stream收集终止操作配合使用
java8 Stream API
java8 Stream API

2)代码示例

	@Test
    public void test6(){
        //1.collection(Collector c); 配合Collector中的静态方法,将Stream过滤终止后的数据
        //收集为其他类型,例如List, set等

        List<Persion> persionList = new ArrayList<>();

        persionList.add(new Persion("小明", 22, 2000.00));
       	//add()......

        //查找工资大于2000的员工返回List,或set
        List<Persion> pList = persionList.stream().filter(p -> p.getSalary()>2000).collect(Collectors.toList());
        pList.forEach(System.out :: println);
        //返回set集合
        Set<Persion> collect = persionList.stream().filter(p -> p.getSalary() > 2000).collect(Collectors.toSet());
        //返回Collection,根据toCollection中的类型来决定返回值的类型
        ArrayList<Persion> collect1 = persionList.stream().filter(p -> p.getSalary() > 2000)
        			.collect(Collectors.toCollection(ArrayList::new));
    }