• Java------Stream流式编程高级API【mapTo、Collectors】(五)


    Java------Stream流式编程高级API【mapTo、Collectors、groupingBy、flatMap】(五)

    mapTo,折叠操作

    折叠操作又称为规约操作,是从一系列输入元素中,通过组合操作组成单个摘要结果。比如:查找一组数字的和、最大值、最小值、个数等。
    常用的折叠操作:
    max()、min()、count()、sum()、groupby()、groupby()+max()。
    以上为了方便对纯数字的流进行处理。
    提供了三种基本类型的Stream
    IntStream、DoubleStream、LongStream。
    通过Stream接口中的三个方法可以得到这三个对象。

    IntStream mapToInt(ToIntFunction<? super T> mapper);
    //ToIntFunction函数式接口,放lamba表达式
    @FunctionalInterface
    public interface ToIntFunction<T> {
    
        /**
         * Applies this function to the given argument.
         *
         * @param value the function argument
         * @return the function result
         */
        int applyAsInt(T value);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    LongStream mapToLong(ToLongFunction<? super T> mapper);
    
    • 1
    DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
    
    • 1

    示例一:得到数字流,求最大、最小

        @Test
        public void test1() {
            int[] intArr = new int[]{1,2,3,4,5,1,2};
            IntStream stream = Arrays.stream(intArr);
            //求个数
            long count = stream.count();
            System.out.println(count);
            //求最大值
            OptionalInt max = Arrays.stream(intArr).max();
    //        int asInt = stream.max().getAsInt();
            //直接输出max会报错,
            System.out.println(max);
    //        System.out.println(asInt);
            //求最小值 会报错, stream has already been operated upon or closed
            OptionalInt min = stream.min();
            System.out.println(min);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    其中调用max值时,返回的类型是OptionalInt,打印输出的结果时:OptionalInt[5],如果想获取它的value。则需要调用getAsInt()方法。

    OptionalInt max = Arrays.stream(intArr).max();
    
    • 1

    根据源码:如果没有值的话,会抛出异常,有值,则返回value

        public int getAsInt() {
            if (!isPresent) {
                throw new NoSuchElementException("No value present");
            }
            return value;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    而流直接调用max方法,也会抛出异常,stream has already been operated upon or closed。此时需要新建一个流

    OptionalInt min = stream.min();
    Arrays.stream(intArr).min();
    
    • 1
    • 2

    案例二:List数组、map进行数字流处理

            @Test
        public void test1() {
            Map<String,Integer> map = new HashMap<>();
            map.put("a",1);
            map.put("b",2);
            map.put("c",3);
            map.put("d",4);
            map.put("e",5);
            Stream<Map<String, Integer>> map1 = Stream.of(map);
            long a = map1.mapToInt(x -> x.get("a")).count();
            //1
            System.out.println(a);
    
            List<Studengt> list = new ArrayList<>();
            list.add(new Studengt("aa",1));
            list.add(new Studengt("bb",2));
            list.add(new Studengt("cc",9));
            OptionalInt max = list.stream().mapToInt(x -> x.getAge()).max();
            //9
            System.out.println(max.getAsInt());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    Collectors 实现将流转list、set、map

    使用Collectors收集器,实现对流进行可变的折叠操作。将流转成List、Set、Map。
    在Stream接口中有一个collect方法收集器进行操作
    collect源码

    <R, A> R collect(Collector<? super T, A, R> collector);
    
    • 1

    Collector源码

    public interface Collector<T, A, R> {
    
    • 1

    如何得到收集器对象?在收集器中制定了转换list、map、set的方法。
    在collectors中定义了很多收集器创建方法,toList实现转list、toSet转set,toMap转map。
    1.创建流对象
    2.创建收集器对象
    3.执行stream流对象的collection方法,进行收集,转成List、set、Map。

    案例三:stream转List。

            String[] strArr = new String[]{"a","bb","ccc","dddd"};
            //默认返回arrylist
            List<String> collect = Arrays.stream(strArr).collect(Collectors.toList());
            collect.stream().forEach(System.out::println);
            //指定linkList,LinkedList::new构造方法引用
            LinkedList<String> collect1 = Arrays.stream(strArr).collect(Collectors.toCollection(LinkedList::new));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    案例四:基本类型数组转流对象

    int数组调用stream方法,返回的时IntStream对象,这样的对象时无法调用。

            int[] intArr = new int[]{1,22,333,4444,55555};
            //语句报错无法执行
            Arrays.stream(intArr).collect(Collectors.toList());
    
    • 1
    • 2
    • 3

    此时调用的collect方法时,另一个需要传入三个参数的方法。

    <R> R collect(Supplier<R> supplier,
                      ObjIntConsumer<R> accumulator,
                      BiConsumer<R, R> combiner);
    
    • 1
    • 2
    • 3

    如果想要正常转List,则需要调用.stream().boxed()方法。
    .boxed():将流中的元素进行装箱,将基本类型的数组转成含有包装类的流。

    如代码所示

    int[] intArr = new int[]{1,22,333,4444,55555};
            //语句报错无法执行
            List<Integer> collect1 = Arrays.stream(intArr).boxed().collect(Collectors.toList());
    
    • 1
    • 2
    • 3

    案例五:list转Map,方法一样,但是map需要指定key、和value,转为年龄为key,Student对象为value的Map

            List<Studengt> list = new ArrayList<>();
            list.add(new Studengt("aa",1));
            list.add(new Studengt("bb",2));
            list.add(new Studengt("cc",9));
            Map<Integer, Studengt> collect1 = list.stream().collect(Collectors.toMap(x -> x.getAge(), x -> x));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    map中key唯一,当使用合并流,流转map时,如果指定的key一样,则会报错,但也有解决办法

            List<Studengt> list = new ArrayList<>();
            list.add(new Studengt("aa",1));
            list.add(new Studengt("bb",2));
            list.add(new Studengt("cc",9));
            List<Studengt> list2 = new ArrayList<>();
            list2.add(new Studengt("aa",1));
            list2.add(new Studengt("bbc",8));
            list2.add(new Studengt("ddd",9));
            Stream.concat(list.stream(),list2.stream()).collect(Collectors.toMap(x->x.getAge(),x->x));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    两个map的key冲突时,解决办法:指定冲突时,使用哪一个value。

    List<Studengt> list = new ArrayList<>();
            list.add(new Studengt("aa",1));
            list.add(new Studengt("bb",2));
            list.add(new Studengt("cc",9));
            List<Studengt> list2 = new ArrayList<>();
            list2.add(new Studengt("aa",1));
            list2.add(new Studengt("bbc",8));
            list2.add(new Studengt("ddd",9));
    Map<Integer, Studengt> collect = Stream.concat(list.stream(), list2.stream()).collect(Collectors.toMap((x) -> x.getAge(), x -> x, (x1, x2) -> x1));
            collect.forEach((key,va)-> System.out.println(key+"+++++"+va));
            //输出结果
    1+++++Studengt{name='aa', age=1}
    2+++++Studengt{name='bb', age=2}
    8+++++Studengt{name='bbc', age=8}
    9+++++Studengt{name='cc', age=9}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    默认是HashMap类型,如何指定为TreeMap类型?
    与List指定LinkList一样,传入构造方法的引用,此时是自然排序

    Map<Integer, Studengt> collect = Stream.concat(list.stream(), list2.stream()).collect(Collectors.toMap((x) -> x.getAge(), x -> x, (x1, x2) -> x1, TreeMap::new));
    
    • 1

    如何指定为TreeMap类型,指定排序,不用自然排序?

    Supplier<TreeMap<Integer,Studengt>> treeMapSupplier = ()->new TreeMap<>(Comparator.reverseOrder());
            Map<Integer, Studengt> collect = Stream.concat(list.stream(), list2.stream()).collect(Collectors.toMap((x) -> x.getAge(), x -> x, (x1, x2) -> x1, treeMapSupplier));
            collect.forEach((key,va)-> System.out.println(key+"+++++"+va));
    
    • 1
    • 2
    • 3

    List转Set

    如果使用TreeSet,则元素需要实现Compare接口
    实体类改造:

    public class Studengt implements Comparable<Studengt>{
    @Override
        public int compareTo(Studengt o) {
            return this.getAge()-o.getAge();
        }
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    示例六List转Set

            System.out.println("===========hashSet=============");
            //转set,默认hashset
            Set<Studengt> collect = concat.collect(Collectors.toSet());
            collect.forEach(System.out::println);
            System.out.println("===========TreeSet,默认排序=============");
            //转TreeSet
            TreeSet<Studengt> collect2 = Stream.concat(list.stream(), list2.stream()).collect(Collectors.toCollection(TreeSet::new));
            collect2.forEach(System.out::println);
            System.out.println("===========TreeSet,age降序排序=============");
            //转TreeSet,并且指定age降序排序
            Supplier<TreeSet<Studengt>> treeSetSupplier = ()->new TreeSet<>((o1,o2)->(int)(o2.getAge()-o1.getAge()));
            TreeSet<Studengt> collect3 = Stream.concat(list.stream(), list2.stream()).collect(Collectors.toCollection(treeSetSupplier));
            collect3.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    博客园主题样式更改总结
    poj 1068 parencondings
    Flink-源算子Source(获取数据源)的使用
    Nature Microbiology | SeqCode:基于序列数据描述的原核生物命名规则
    Webfunny大版本改造(mysql迁移至clickhouse)
    配置vscode免密登录本地Ubuntu
    消息队列常见问题
    科技的成就(二十七)
    俄罗斯方块游戏开发教程5:形状碰撞检测(下)
    OceanBase年度发布会归来
  • 原文地址:https://blog.csdn.net/cz_chen_zhuo/article/details/126129230