stream的collectors

news2024/11/17 16:38:09

起因的话,新进公司,看见了一段有意思的代码。

public final class MyCollectors {
   
    private MyCollectors() {

    }

    static final Set<Collector.Characteristics> CH_ID = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));


    static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
        private final Supplier<A> supplier;
        private final BiConsumer<A, T> accumulator;
        private final BinaryOperator<A> combiner;
        private final Function<A, R> finisher;
        private final Set<Characteristics> characteristics;



        CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Function<A, R> finisher,
                Set<Characteristics> characteristics) {
            this.supplier = supplier;
            this.accumulator = accumulator;
            this.combiner = combiner;
            this.finisher = finisher;
            this.characteristics = characteristics;
        }

       
        CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Set<Characteristics> characteristics) {
            this(supplier, accumulator, combiner, castingIdentity(), characteristics);
        }

        @Override
        public BiConsumer<A, T> accumulator() {
            return accumulator;
        }

        @Override
        public Supplier<A> supplier() {
            return supplier;
        }

        @Override
        public BinaryOperator<A> combiner() {
            return combiner;
        }

        @Override
        public Function<A, R> finisher() {
            return finisher;
        }

        @Override
        public Set<Characteristics> characteristics() {
            return characteristics;
        }
    }

    @SuppressWarnings("unchecked")
    private static <I, R> Function<I, R> castingIdentity() {
        return i -> (R) i;
    }

 
    public static <T> Collector<T, ?, Page<T>> toPage() {
        return new CollectorImpl<>((Supplier<Page<T>>) () -> new Page<T>(), Page::add, (left, right) -> {
            left.addAll(right);
            left.setTotal(1);
            return left;
        }, CH_ID);
    }
}

这个,我们基本也能猜到这个代码主要用处,应该是toPage,应该是将list转换为page对象。

但是我们平常的用法的话,基本都是自己构建对象,自己塞。或者stream的map,然后我们用一个枚举类,常量类的function<list,Page>这样的来转换list到page。这里实现了一个自己的收集器,就比较新颖。

但是我有点搞不懂各个参数的具体意义。那怎么办呢?我就想到,我应该是哪里看到过博客,果然还是得瞎几把看看,这样起码知道讲的是什么,要去哪找。

深度探秘 Java 8 函数式编程(上)_mb60f8d1355165a的技术博客_51CTO博客

可以进去看看,

他这里说的是,

四要素
一个聚合器的实现,通常需要提供四要素:

一个结果容器的初始值提供器 supplier ;

一个用于将每次二元操作的中间结果与结果容器的值进行操作并重新设置结果容器的累积器 accumulator ;

一个用于对Stream元素和中间结果进行操作的二元操作符 combiner ;

一个用于对结果容器进行最终聚合的转换器 finisher(可选) 。

那我们也实习一个自己的收集器,就实现一个累加器吧。

public class FiboCollector implements Collector<Integer, List<Integer>, Integer> {

    public Supplier<List<Integer>> supplier() {
        return () -> {
            List<Integer> result = new ArrayList<>();
            return result;
        };
    }

    @Override
    public BiConsumer<List<Integer>, Integer> accumulator() {
        return (res, num) -> {
            if(res.size()==0){
                res.add(num);
            }else{
                Integer integer = res.get(0);
                res.set(0,integer+num);
            }
        };
    }

    @Override
    public BinaryOperator<List<Integer>> combiner() {

        return (left, right) -> {
            System.out.println(left);
            System.out.println(right);
            return left;
        };
    }

    @Override
    public Function<List<Integer>, Integer> finisher() {
        return x->{ return x.get(0);};
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.emptySet();
    }

    public static void main(String[] args) {

        Integer collect = Arrays.asList(2, 2, 3, 4, 5, 6, 7, 8, 9, 10).stream().collect(new FiboCollector());
        System.out.println(collect);
    }
}

这里容器的话,supplier按道理应该返回intteger的,但是考虑到累加器accumulator的话,因为是一个没有返回值的,那么应该是覆盖的,但是感觉不太对,然后想起来那我用finisher最后处理的时候,返回interger不就好了。之前容器用list不就好了,于是就写出这么一段代码。但是问题又来了combiner是干嘛用的。

一个用于对Stream元素和中间结果进行操作的二元操作符 combiner ;

不太对吧,我debug看,也没有走到这段代码。

遇事不决就百度。

(66条消息) 关于java Stream中的reduce使用和为什么要有combiner_Cyberin的博客-CSDN博客

图片讲的很清楚了,就是没用并行流之前,用的combiner,如果用parallel,应该是几个元素执行完combiner后,要合并的是,你要做的操作。那么我们肯定是两个list拿第一个元素,然后加完以后,返回一个list。

public class FiboCollector implements Collector<Integer, List<Integer>, Integer> {

    public Supplier<List<Integer>> supplier() {
        return () -> {
            List<Integer> result = new ArrayList<>();
            return result;
        };
    }

    @Override
    public BiConsumer<List<Integer>, Integer> accumulator() {
        return (res, num) -> {
            if(res.size()==0){
                res.add(num);
            }else{
                Integer integer = res.get(0);
                res.set(0,integer+num);
            }
        };
    }

    @Override
    public BinaryOperator<List<Integer>> combiner() {

        return (left, right) -> {
            System.out.println(left);
            System.out.println(right);
            int i = left.get(0) + right.get(0);
            List<Integer> data =new ArrayList<>();
            data.add(i);
            return data;
        };
    }

    @Override
    public Function<List<Integer>, Integer> finisher() {
        return x->{ return x.get(0)+;};
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.emptySet();
    }

    public static void main(String[] args) {

        Integer collect = Arrays.asList(2, 2, 3, 4, 5, 6, 7, 8, 9, 10).stream().parallel().collect(new FiboCollector());
        System.out.println(collect);
    }
}

执行也可以看到,打印出sout了。

一个用于parallel 对中间结果进行操作合并操作的二元操作符 combiner ;

这样每个元素我们就知道怎么实现了,那么我们就基本知道套路了。

我们可以去看看collects。集合聚合器 toSet(), 字符串连接器 joining(),以及列表求和(summingXXX)、最大(maxBy)、最小值(minBy)等都是这个套路。

public static <T>
    Collector<T, ?, List<T>> toList() {
        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_ID);

那么我们能用他干嘛,我这里的话,只能想到上面的list转page。算是扩展点吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/496899.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开源中国面试准备

dockerFile常见命令 1、FROM 设置要制作的镜像基于哪个镜像&#xff0c;FROM指令必须是整个Dockerfile的第一个指令&#xff0c;如果指定的镜像不存在默认会自动从Docker Hub上下载 2、MAINTAINER 镜像作者的信息&#xff0c;比如名字或邮箱地址 语法&#xff1a;MAINTAINER n…

HTTP第三讲——四层模型、七层模型

四层模型 TCP/IP 协议&#xff0c;它是 HTTP 协议的下层协议&#xff0c;负责具体的数据传输 工作。TCP/IP 协议是一个“有层次的协议栈”。 TCP/IP 当初的设计者真的是非常聪明&#xff0c;创造性地提出了“分层”的概念&#xff0c;把复杂的网络通信划分出多个层次&#xff…

免费矢量图标网站有哪些?

图标作为UI设计的必要元素&#xff0c;矢量图标是质量的保证。据说完美的用户体验应该从灵活性开始 。在响应设计盛行的当下&#xff0c;灵活矢量图标的重要性不言而喻。在这种情况下&#xff0c;风格齐全、质量上乘的矢量图标网站堪称设计宝藏。在这篇文章中&#xff0c;我们…

基于springboot的医院信管系统

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&…

读书笔记--数据治理之法

继续延续上一篇文章&#xff0c;对数据治理之法进行学习。数据治理之法是战术层面的方法&#xff0c;是一套涵盖8项举措的数据治理实施方法论&#xff0c;包括梳理现状与确定目标、能力成熟度评估、治理路线图规划、保障体系建设、技术体系建设、治理策略执行与监控、绩效考核与…

c++学习:STL之string类初识

目录 1.关于STL 1.什么是STL 2.STL的六的组件 2.关于string类的学习 1.为何学习string类 2.何为string类 3.string类对象的构造 4.容量操作 5.元素访问的操作 6.迭代器&#xff08;Iterators&#xff09; 7.修改类的操作 8.字符串操作 1.关于STL 1.什么是STL STL&a…

理解多态的实现原理

目录 概念&#xff1a; 特例&#xff1a; 协变&#xff1a; final&#xff1a; override: 抽象类、纯虚函数&#xff1a; 查表&#xff1a; 动态绑定&#xff1a; 概念&#xff1a; 就是多个不同的对象&#xff0c;在完成某种相同动作时&#xff0c;会产生多种不同的状态…

佩戴更舒适的骨传导耳机,音质也很出色,南卡 NEO体验

现在天气越来越好&#xff0c;特别适合户外运动&#xff0c;很多人跑步健身时都喜欢戴上一副骨传导耳机&#xff0c;听音乐的同时&#xff0c;还可以随时留意周围的交通状况。在国产的骨传导耳机里面&#xff0c;南卡是很受欢迎的一个品牌&#xff0c;而且旗下产品非常丰富&…

基于Redis优化验证码登录流程, 解决登录状态刷新问题

文章目录 1 问题: 多台Tomcat间session共享问题2 Redis代替session的业务流程分析2.1 设计key的结构2.2 设计Key的具体细节2.3 整体访问流程 3 基于Redis实现短信登录4 解决状态登录刷新问题4.1 初始方案问题4.2 优化方案4.3 代码 1 问题: 多台Tomcat间session共享问题 书接上…

Linux 内存分配/内存管理 相关接口

Linux 内存分配/内存管理 相关接口 分配栈内存alloca() 分配堆内存直接分配malloc() 分配初始化空间calloc() 分配对齐空间posix_memalign()aligned_alloc()过时&#xff1a;memalign()过时&#xff1a;valloc()过时&#xff1a;pvalloc() 修改块的大小realloc()reallocarray()…

20230506在Ubuntu22.04下使用python3下载合并ts切片

20230506在Ubuntu22.04下使用python3下载合并ts切片 2023/5/6 19:42 本文主要是和WIN7/WIN10下的差异比对&#xff01; 一、 Z:\1575\buquan-ts1574.py import requests from multiprocessing import Pool def mission(url,n): headers {"User-Agent":"M…

php语法基础

基础语法 1&#xff0c;php标记符 ①&#xff0c;XML风格 <?php echo "这是标准风格的标记"; ?>②脚本风格 <script language"php"> echo 这是脚本风格的标记; </script>③简短风格 <? echo "这是简短风格的标记"…

62.网页设计规则#8_视觉层次

什么是视觉层次&#xff1f; 视觉层次是关于确定设计中哪些元素是最重要的。视觉层次是为了吸引人们的注意力关注这些最重要的元素。视觉层次是关于为用户定义一个“路径”,引导他们浏览页面我们使用位置、大小、颜色、间距、边框和阴影的组合来建立元素/组件之间有意义的视觉…

leetcode:环形链表(详解)

前言&#xff1a;内容包括-题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读&#xff0c;拓展问题 题目&#xff1a; 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&…

【BIM+GIS】Supermap打开BIM Revit模型的方式

Revit导出Supermap GIS格式数据的方法通常有三种:插件式导出、直接导入和标准交换格式(IFC)导出。 文章目录 一、Revit安装Supermap插件1. 安装Supermap插件2. UDB导出模型3. 打开模型二、Revit导出IFC格式1. Revit导出IFC2. Supermap导入IFC一、Revit安装Supermap插件 1. …

115-Linux_C语言访问mysql及操作数据库

文章目录 一.C语言访问mysql1.连接数据库使用的头文件和库文件2.初始化连接句柄3.连接数据库4.关闭连接5.执行sql语句6.提取结果7.获取结果集中有多少行8.取出结果集中的一行记录9.查看记录行的列数10.释放结果集占用的内存11.获取错误信息 二.连接数据库三.操作数据库 一.C语言…

Linux 中实现 ssh 免密登录

Linux 中实现 ssh 免密登录 1. 使用命令行 在控制端使用命令生成私钥密钥对&#xff0c;执行命令 ssh-keygen -t rsa ,一路默认回车即可&#xff0c;然后会在 .ssh/ 目录下生成两个文件 id_rsa 和 id_rsa.pub&#xff0c;如下图。 使用命令 ssh-copy-id root192.168.16.4&…

电力NLP:指令票规范识别

文章目录 任务目的想法讲解数据集介绍1电气主语2操作任务判断数据集3操作内容判断数据集4错误词数据集 解法讲解程序、数据集下载链接 任务目的 识别调度指令票&#xff08;或者其它操作票&#xff09;是否规范。 想法讲解 按石第2014—16号定值单投入石双西线161开关6区保护…

web三大作用域+servlet生命周期

Web三大作用域 Application ServlectContext &#xff1a; 作用于整个web应用&#xff0c;随程序的停止而失效。 使用&#xff1a; request.getServletContext().setAttribute("参数名","参数值");//servlet获取Application对象并传入数据 Application.g…

React antd 日期选择控件踩坑 <DatePicker> Table Ant Design ProTable

背景 需求&#xff1a;一个带日期的字段 后端接口给值时默认设置为这个日期值 不给值时就是默认状态 <DatePicker defaultValue{val} onChange{handleChange} {...props} />这里 val 是我最终从后端获取到的日期数据 可能有值可能没有值 按照官方 API 和 demo 写 应…