山寨Stream API

news2024/9/30 13:15:47
作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

一个需求

List<Person> list = new ArrayList<>();

list.add(new Person("李健", 46));

list.add(new Person("周深", 28));

list.add(new Person("张学友", 59));

请筛选出年龄大于40的歌手的名字

请大家先自行实现这个需求。

我的实现方式

我写了一个山寨版的Stream API,实现了其中的filter()和map(),底层原理稍有不同,仅做知识引入。

乍一看很麻烦,好像还不如直接写各种for,但我是为了复用,所以抽取了MyList类。

要想实现上面的编码形式,需要两块砖:

  • 链式编程
  • 把Lambda表达式作为接口实例传递(必须是函数式接口)

关于Lambda表达式,请参考《Lambda表达式》。

链式编程简单来说就是一个方法返回引用本身:

public class ChainCall {
    public static void main(String[] args) {
        Person bravo1988 = new Person().setName("mx").setAge(18).setMoney(1000.0);
    }
}

class Person{
    private String name;
    private Integer age;
    private Double money;

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

    public Double getMoney() {
        return money;

    }
    
    public Person setName(String name) {
        this.name = name;
        // set方法要返回this,方便继续调用下一个set
        return this;
    }
    
    public Person setAge(Integer age) {
        this.age = age;
        return this;
    }

    public Person setMoney(Double money) {
        this.money = money;
        return this;
    }
}

OK,交代完毕,接下来请大家把我的代码拷贝到本地运行看看:

/**
 * @author mx
 */
public class MockStream {

    public static void main(String[] args) throws JsonProcessingException {

        MyList<Person> personMyList = new MyList<>();
        personMyList.add(new Person("李健", 46));
        personMyList.add(new Person("周深", 28));
        personMyList.add(new Person("张学友", 59));

        // 需求:过滤出年龄大于40的歌手的名字
        MyList<String> result = personMyList.filter(person -> person.getAge() > 40).map(Person::getName);
        prettyPrint(result.getList());

        System.out.println("\n---------------------------------------------\n");

        // 对比真正的Stream API
        List<Person> list = new ArrayList<>();
        list.add(new Person("李健", 46));
        list.add(new Person("周深", 28));
        list.add(new Person("张学友", 59));

        List<String> collect = list
                .stream()                               // 真正的Stream API需要先转成stream流
                .filter(person -> person.getAge() > 40) // 过滤出年纪大于40的歌手
                .map(Person::getName)                   // 拿到他们的名字
                .collect(Collectors.toList());          // 整理成List<String>

        prettyPrint(collect);
    }


    /**
     * 按JSON格式输出
     *
     * @param obj
     * @throws JsonProcessingException
     */
    private static void prettyPrint(Object obj) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        String s = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        System.out.println(s);
    }


}


@Data
@AllArgsConstructor
class Person {
    private String name;
    private Integer age;
}

@Getter
class MyList<T> {
    private List<T> list = new ArrayList<>();

    public boolean add(T t) {
        return list.add(t);
    }

    /**
     * 给MyList传递具体的判断规则,然后MyList把内部现有符合判断(true)的元素集返回
     * @param predicate
     * @return
     */
    public MyList<T> filter(Predicate<T> predicate){
        MyList<T> filteredList = new MyList<>();

        for (T t : list) {
            if (predicate.test(t)) {
                // 收集判断为true的元素
                filteredList.add(t);
            }
        }

        return filteredList;
    }

    /**
     * 把MyList中的List<T>转为List<R>
     *
     * @param mapper
     * @param <R>
     * @return
     */
    public <R> MyList<R> map(Function<T, R> mapper) {
        MyList<R> mappedList = new MyList<>();

        for (T t : list) {
            mappedList.add(mapper.apply(t));
        }

        return mappedList;
    }

}

/**
 * 定义一个Predicate接口,名字无所谓
 *
 * @param <T>
 */
@FunctionalInterface
interface Predicate<T> {
    /**
     * 定义了一个test()方法,传入任意对象,返回true or false,具体判断逻辑由子类实现
     *
     * @param t
     * @return
     */
    boolean test(T t);
}


/**
 * 定义一个Function接口,名字无所谓
 *
 * @param <E>
 * @param <R>
 */

@FunctionalInterface
interface Function<E, R> {
    /**
     * 定义一个apply()方法,接收一个E返回一个R。也就是把E映射成R
     *
     * @param e
     * @return
     */
    R apply(E e);
}

看不懂没关系,感受一下即可。

下一篇会带着大家一步步分析上面的代码是怎么写出来的。

正所谓画龙画虎难画骨,山寨Stream API毕竟只是山寨版。

MyList虽然很像Stream API,但本质还是对List进行外部迭代,而正版的Stream API是先产生Stream流,再通过流迭代,属于内部迭代。两者其实存在本质区别。

本文只是借助这个例子切入Stream API的学习,你们也不可能在实际项目中放着正版Stream API不用,而拷贝我的山寨版。

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

进群,大家一起学习,一起进步,一起对抗互联网寒冬

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

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

相关文章

LeetCode [简单](非递归)二叉树的中序遍历

遍历左孩子&#xff0c;将他们放进栈中&#xff0c;左边走到尽头&#xff0c;出栈&#xff0c;root变为栈顶元素&#xff0c;存值&#xff0c;向右边走一个 再次遍历左孩子&#xff0c;将他们放入栈中&#xff0c;如果没有左孩子了&#xff0c;就出栈&#xff0c;root变为栈顶…

Rocky Linux 9.3 为 PowerPC 64 位带回云和容器镜像

导读RHEL 克隆版 Rocky Linux 9.3 今天发布了&#xff0c;作为红帽企业 Linux 发行版 CentOS Stream 和 Red Hat Enterprise Linux 的免费替代版本&#xff0c;现在可供下载。 Rocky Linux 9.3 是在 Rocky Linux 9.2 发布 6 个月之后发布的&#xff0c;它带回了 PowerPC 64 位…

Mysql锁实战详细分析

1.mysql回表查询 在这里提起主要是用于说明mysql数据和索引的结构&#xff0c;有助于理解后续加锁过程中的一些问题。 mysql索引结构和表数据结构是相互独立的&#xff0c;根据索引查询&#xff0c;只能找到索引列和主键聚簇索引。如果select语句中不包含索引列&#xff0c;m…

SpringBoot自动配置注入Bean工具autoconfigure

依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency> yml配置 student:red: com.ma.config.MinIOConfigProperties spring.factories org.springframework.…

Python提取PDF表格(基于AUTOSAR_SWS_CANDriver.pdf)

个人学习笔记&#xff0c;仅供参考。 需求&#xff1a;提取AUTOSAR SWS中所有的API接口信息&#xff0c;用于生成C代码。 此处以AUTOSAR_SWS_CANDriver.pdf为例&#xff0c;若需要提取多个SWS文件&#xff0c;遍历各个文件即可。 1.Python包 pdfplumber是一款完全用python开…

Mysql解决随机选取问题

常规的随机选取效率差的原因&#xff1a; 两种解决方法&#xff1a; 总结&#xff1a;

VUE语法--img图片不显示/img的src动态赋值图片显示

1、问题概述 常见情景1&#xff1a;在VUE中使用img显示图片的时候&#xff0c;通过传参的方式传入图片的路径和名称&#xff0c;VUE不加载本地资源而是通过http://localhost:8080/...的地址去加载网络资源&#xff0c;从而出现了图片无法显示的情况。 常见情景2&#xff1a;针…

C#使用WebSocket进行链接

C#使用WebSocket进行网络链接&#xff0c;和服务端搭建一个长连接进行通信。 有两种方式&#xff1a;串口方式&#xff08;SerialPort&#xff09;和网口方式&#xff08;Socket 包括&#xff1a;TcpClient和UdpClient&#xff09; 准备&#xff1a; 1.C#使用WebSocket的一种…

【vue_3】关于超链接的问题

1、需求2、修改前的代码3、修改之后&#xff08;1&#xff09;第一次&#xff08;2&#xff09;第二次&#xff08;3&#xff09;第三次&#xff08;4&#xff09;第四次&#xff08;5&#xff09;第五次 1、需求 需求&#xff1a;要给没有超链接的列表添加软超链接 2、修改前…

4.Spring源码解析-loadBeanDefinitions(XmlBeanDefinitionReader)

第一个点进去 发现是空 肯定走的第二个逻辑了 这里在这里已经给属性设置了值&#xff0c;所以肯定不是空能拿到。 1.ClassPathXmlApplicationContext 总结&#xff1a;该loadBeanDefinitions是XmlBeanDefinitionReader设置xml文件在哪。

4D雷达目标检测跟踪算法设计

1.算法流程 4D雷达点云跟踪处理沿用3D毫米波雷达的处理流程&#xff0c;如下图&#xff1a; 从接收到点云开始&#xff0c;先对点云做标定、坐标转换、噪点剔除、动静分离&#xff0c;再分别对动态目标和静态目标做聚类&#xff0c;然后根据聚类结果做目标的特征分析和检测等&a…

Linux - 动静态库(上篇)

Linux 当中的 内存管理模块 不管是操作系统对于进程之间的管理&#xff0c;还是 对于文件的访问和修改等等的操作&#xff0c;都是要把数据加载到内存当中的&#xff0c;所以&#xff0c;所有的工作都离不开 内存管理模块。 内存的本质其实是对数据的一种临时存储&#xff0c…

Linux shell for jar test

Linux shell 脚本&#xff0c;循环解析命令行传入的所有参数&#xff0c;并按照不同的传参实现对不同的 java jar文件 进行测试执行。 [rootlocalhost demo]# cat connTest.sh #!/bin/bash# Linux shell for qftool java jar test# modes DEFAULT_MODE2jarfiles[1]common-1.0…

Redis 两种持久化方式 AOF 和 RDB

目录 一、Redis 的持久化 二、Redis 的持久化方式 RDB RDB 介绍 RDB 的触发方式&#xff1a;. 三、RDB的文件生成策略 四、Save 和 Bgsave 命令的区别 六、RDB 最佳配置 七、触发机制-不容忽略方式 AOF 一、AOF介绍 二、RDB所存在的问题 三、AOF 三种策略 四、AOF…

linux zsh终端美化

目前的centos系统默认的shell还是bash&#xff0c;但是zsh被称为终极shell&#xff0c;国外有个程序员开发出了一个能够让你快速上手的zsh项目&#xff0c;叫做「oh my zsh」&#xff0c;Github 网址是&#xff1a;https://github.com/robbyrussell/oh-my-zsh 有了这玩意zsh用起…

vue3中的动态component组件

is属性来指定要渲染的组件(填写组件名&#xff09; 多个子组件通过component标签挂载在同一个父组件中&#xff0c; 可以修改is属性进行动态切换组件。 可以搭配<keep-alive></keep-alive>使用。 父组件代码&#xff1a; <template><div style"fon…

Linux系统下查询指定网卡的型号及用途

接到应用侧的特殊要求&#xff0c;需要查询服务器上特定网口的物理型号及配置用途&#xff0c;发现没有一条现成指令可以完成此事。经测试&#xff0c;可按以下步骤执行3条命令来组合完成。 一、使用lspci命令来查询指定网卡的型号 按照以下步骤进行操作&#xff1a; 打开终…

基于振弦式轴力计和采集仪的安全监测解决方案

基于振弦式轴力计和采集仪的安全监测解决方案 振弦式轴力计是一种测量结构物轴向力的设备&#xff0c;通过测量结构物上的振弦振幅变化&#xff0c;可以确定结构物轴向力的大小。采集仪是一种用于采集和存储传感器数据的设备&#xff0c;通常与振弦式轴力计一起使用&#xff0c…

【无标题】【教3妹学编程-算法题】设计前中后队列

3妹&#xff1a;好冷啊&#xff0c; 冻得瑟瑟发抖啦 2哥 : 又一波寒潮来袭&#xff0c; 外面风吹的呼呼的。 3妹&#xff1a;今天还有雨&#xff0c;2哥上班记得带伞。 2哥 : 好的 3妹&#xff1a;哼&#xff0c;不喜欢冬天&#xff0c;也不喜欢下雨天&#xff0c;要是我会咒语…

FPGA模块——DA转换模块(AD9708类)

FPGA模块——DA转换模块&#xff08;AD9708类&#xff09; AD9708/3PD9708代码 AD9708/3PD9708 由于电路接了反相器&#xff0c;所以对应就不一样了。 电路图&#xff1a; 代码 在ROM中存入要输出的波形数据&#xff1a; 用软件生成各个对应的点。 给DA转换器一个时钟&…