Bootstrap

stream流详解

Stream流

一 :Stream流的介绍

  1. stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果;
  2. stream不会改变数据源,通常情况下会产生一个新的集合;
  3. stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
  4. stream操作分为终端操作和中间操作,那么这两者分别代表什么呢?
    终端操作:会消费流,这种操作会产生一个结果的,如果一个流被消费过了,那它就不能被重用的。
    中间操作:中间操作会产生另一个流。因此中间操作可以用来创建执行一系列动作的管道。一个特别需要注意的点是:中间操作不是立即发生的。相反,当在中间操作创建的新流上执行完终端操作后,中间操作指定的操作才会发生。所以中间操作是延迟发生的,中间操作的延迟行为主要是让流API能够更加高效地执行。
  5. stream不可复用,对一个已经进行过终端操作的流再次调用,会抛出异常。

二: 创建流

public class Demo1 {
    public static void main ( String[] args ) {
        //创建stream流,通过Arrays.stream
        int[] arr = {1, 2, 3};
        IntStream stream = Arrays.stream(arr);
        Person[] personStr = {new Person(18, "xiaoliu"), new Person(18, "xiaojing")};
        Stream<Person> personStream = Arrays.stream(personStr);
        // 通过stream.of
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4);
        // 通过集合创建流
        List<String> stringList = Arrays.asList("123", "456", "789");
        // 创建普通流
        Stream<String> stringStream = stringList.stream();
        // 创建并行流
        Stream<String> parallelStream = stringList.parallelStream();

    }
}

public class Demo2 {
    public static void main ( String[] args ) {
        // 流的筛选
        List<Integer> integerList = Arrays.asList(1, 2, 3,3, 4, 5, 6);
        // 筛选出集合中数字大于4的元素
        List<Integer> collect = integerList.stream().filter(x -> x > 4).collect(Collectors.toList());
        System.out.println(collect); //[5, 6]
        // 集合中的去重
        List<Integer> collect1 = integerList.stream().distinct().collect(Collectors.toList());
        System.out.println(collect1);//[1, 2, 3, 4, 5, 6]
        // 获取流中的第一个元素
        Optional<Integer> first = integerList.stream().filter(x -> x > 4).findFirst();
        Optional<Integer> any = integerList.stream().filter(x -> x > 4).findAny();
        Optional<Integer> any1 = integerList.parallelStream().filter(x -> x > 4).findAny();
        System.out.println(first); //Optional[5]
        System.out.println(any); //Optional[5]
        System.out.println(any1); // 预期结果不稳定

    }
}

三:Stream流中获取最值 max、min和count

public class Demo3 {
    public static void main(String[] args) {
        List<String> stringList = Arrays.asList("huainvhai", "xiaotiancai", "bennvhai");
        // 获取集合中最长的字符串
        Optional<String> maxString = stringList.stream().max(Comparator.comparing(String::length));
        // 获取集合中最短字符串
        Optional<String> minString = stringList.stream().min(Comparator.comparing(String::length));
        System.out.println(maxString);
        System.out.println(minString);
        
        
        
        // 获取集合中的最大值
        List<Integer> integerList = Arrays.asList(1, 2, 3);
        Optional<Integer> maxInteger = integerList.stream().max((i, j) -> {
            return i - j;
        });
        // 获取集合中的最小值
        Optional<Integer> minInteger = integerList.stream().max((i, j) -> {
            return j - i;
        });
        System.out.println(maxInteger);
        System.out.println(minInteger);
        
        
        
        
        // 集合泛型是个对象的最值
        ArrayList<Person> personList = new ArrayList<>();
        personList.add(new Person("xiao",12));
        personList.add(new Person("xiao",20));
        personList.add(new Person("xiao",18));
        Optional<Person> max = personList.stream().max(Comparator.comparing(Person::getAge));
        // 获取集合中的元素数量
        long count = personList.stream().filter(p -> p.getAge() > 12).count();
        System.out.println(max);
        System.out.println(count);
    }
}

四: 缩减

缩减:就是把一个流缩减成一个值,比如说对一个集合中求和,求乘积等

Stream流定义了三个reduce

public interface Stream<T> extends BaseStream<T, Stream<T>> {
 // 方法1
 T reduce(T identity, BinaryOperator<T> accumulator);
 // 方法2
 Optional<T> reduce(BinaryOperator<T> accumulator);
 // 方法3
 <U> U reduce(U identity,
          BiFunction<U, ? super T, U> accumulator,
          BinaryOperator<U> combiner);
}

前两种缩减方式

第一种:接收一个BinaryOperator accumulator function(二元累加计算函数)和identity(标示值)为参数,返回值是一个T类型(代表流中的元素类型)的对象。accumulator代表操作两个值并得到结果的函数。identity按照accumulator函数的规则参与计算,假如函数是求和运算,那么函数的求和结果加上identity就是最终结果,假如函数是求乘积运算,那么函数结果乘以identity就是最终结果。

第二种:不同之处是没有identity,返回值是Optional(JDK8新类,可以存放null)。

public class Demo4 {
    public static void main(String[] args) {
        List<Integer> integers = Arrays.asList(1, 2, 3, 4);
        // 写法一 集合中的元素求和 (就是集合中的元素求和再加上1)
        Integer integer = integers.stream().reduce(1, Integer::sum);
        // 写法二
        integers.stream().reduce(1,(x,y)->x+y);
        System.out.println(integer); // 11

        // 第二种缩减方式 集合中的元素求和
        Optional<Integer> reduce = integers.stream().reduce(Integer::sum);
        // 写法二
        Optional<Integer> reduce1 = integers.stream().reduce((x, y) -> x + y);
        System.out.println(reduce); //Optional[10]
        System.out.println(reduce1); //Optional[10]

        // 集合中使用reduce求最值问题
        Optional<Integer> reduce2 = integers.stream().reduce(Integer::max);
        System.out.println(reduce2);

        /**
         * 对象集合求和 求最值问题
         */
        ArrayList<Person> personList = new ArrayList<>();
        personList.add(new Person("xiao",12));
        personList.add(new Person("xiao",20));
        personList.add(new Person("xiao",18));
        // 求集合中对象的年龄的总和
        Optional<Integer> reduce3 = personList.stream().map(p -> p.getAge()).reduce(Integer::sum);
        System.out.println(reduce3);  //Optional[50]

        // 求集合中年龄最大的对象
        Optional<Person> reduce4 = personList.stream().reduce((p1, p2) -> p1.getAge() > p2.getAge() ? p1 : p2);
        Optional<Person> max = personList.stream().max(Comparator.comparingInt(Person::getAge));
        System.out.println(reduce4);
        System.out.println(max);
    }
}

五:collect

collect操作可以接受各种方法作为参数,将流中的元素汇集,

public class Demo5 {
    public static void main(String[] args) {
        ArrayList<Person> personList = new ArrayList<>();
        personList.add(new Person("xiao",12));
        personList.add(new Person("xiao",20));
        personList.add(new Person("xiao",18));
        // 获取平均年龄 averaging
        Double collect = personList.stream().collect(Collectors.averagingInt(Person::getAge));
        System.out.println(collect); //16.666666666666668

        // summarizing
        DoubleSummaryStatistics collect1 = personList.stream().collect(Collectors.summarizingDouble(Person::getAge));
        System.out.println(collect1); // DoubleSummaryStatistics{count=3, sum=50.000000, min=12.000000, average=16.666667, max=20.000000}

        //joining
        String collect2 = personList.stream().map(p -> p.getName()).collect(Collectors.joining(","));
        System.out.println(collect2);  //xiao,xiao,xiao

        // reduce
        Integer collect3 = personList.stream().collect(Collectors.reducing(0, Person::getAge, (x, y) -> x + y));
        Optional<Integer> reduce = personList.stream().map(Person::getAge).reduce(Integer::sum);
        System.out.println(collect3); //50
        System.out.println(reduce);   //Optional[50]

        // groupingBy
        // 以名字进行分组
        Map<String, List<Person>> collect4 = personList.stream().collect(Collectors.groupingBy(Person::getName));
        System.out.println(collect4); //{xiao=[Person(name=xiao, age=12), Person(name=xiao, age=20), Person(name=xiao, age=18)]}
        // 先以名字分组,再以年龄分组
        Map<String, Map<Integer, List<Person>>> collect5 = personList.stream().collect(Collectors.groupingBy(Person::getName, Collectors.groupingBy(Person::getAge)));
        System.out.println(collect5); //{xiao={18=[Person(name=xiao, age=18)], 20=[Person(name=xiao, age=20)], 12=[Person(name=xiao, age=12)]}}

        // toList、toSet、toMap
        Set<Person> collect6 = personList.stream().collect(Collectors.toSet());
        System.out.println(collect6);//[Person(name=xiao, age=18), Person(name=xiao, age=20), Person(name=xiao, age=12)]

    }
}

六:映射

Stream流中,map可以将一个流的元素按照一定的映射规则映射到另一个流中。

public class Demo6 {
    public static void main(String[] args) {
        String[] strArr = { "abcd", "bcdd", "defde", "ftr" };
        Arrays.stream(strArr).map(x->x.toUpperCase()).forEach(System.out::print); //ABCDBCDDDEFDEFTR
        List<String> collect = Arrays.stream(strArr).map(x -> x.toUpperCase()).collect(Collectors.toList());
        System.out.println(collect); // [ABCD, BCDD, DEFDE, FTR]

    }
}

七 排序

Sorted方法是对流进行排序,并得到一个新的stream流,是一种中间操作。Sorted方法可以使用自然排序或特定比较器。

public class Demo7 {
    public static void main(String[] args) {
        String[] strArr = { "ab", "bcdd", "defde", "ftr" };
        // 自然排序
        List<String> collect = Arrays.stream(strArr).sorted().collect(Collectors.toList());
        System.out.println(collect);  // [ab, bcdd, defde, ftr]

        // 自定义排序
        // 按照字符串的长度 长度 从小到大
        List<String> collect1 = Arrays.stream(strArr).sorted(Comparator.comparing(String::length)).collect(Collectors.toList());
        System.out.println(collect1); //[ab, ftr, bcdd, defde]
        // 按照字符串的长度逆序排序
        List<String> collect2 = Arrays.stream(strArr).sorted(Comparator.comparing(String::length).reversed()).collect(Collectors.toList());
        System.out.println(collect2); //[defde, bcdd, ftr, ab]

        // 首字母倒序
        List<String> collect3 = Arrays.stream(strArr).sorted(Comparator.reverseOrder()).collect(Collectors.toList());
        System.out.println(collect3); //[ftr, defde, bcdd, ab]
        // 首字母自然排序
        List<String> collect4 = Arrays.stream(strArr).sorted(Comparator.naturalOrder()).collect(Collectors.toList());
        System.out.println(collect4); //[ab, bcdd, defde, ftr]
    }
}

八 提取流和组合流

public class Demo8 {
    public static void main(String[] args) {
        String[] arr1 = {"a","b","c","d"};
        String[] arr2 = {"d","e","f","g"};
        String[] arr3 = {"i","j","k","l"};

        Stream<String> stream1 = Arrays.stream(arr1);
        Stream<String> stream2 = Arrays.stream(arr2);
        Stream<String> stream3 = Arrays.stream(arr3);
        // 可以把两个stream合并成一个stream(合并的stream类型必须相同),只能两两合并
//        List<String> collect = Stream.concat(stream1, stream2).collect(Collectors.toList());
//        System.out.println(collect); //[a, b, c, d, d, e, f, g]
        // 合并去重
        List<String> collect1 = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
        System.out.println(collect1); //[a, b, c, d, e, f, g]

        // limit,限制从流中获得前n个数据
//        List<String> collect = collect1.stream().limit(3).collect(Collectors.toList());
//        System.out.println(collect); //[a, b, c]

        // skip,跳过前n个数据
        List<String> collect = collect1.stream().skip(1).limit(3).collect(Collectors.toList());
        System.out.println(collect);//[b, c, d]
    }
}
;