当前位置:

首页 > 编程开发 > Java中缺失的特性:扩展方法是什么?

Java中缺失的特性:扩展方法是什么?

什么是扩展方法扩展方法,就是能够向现有类型直接“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改现有类型。调用扩展方法的时候,与调用在类型中实际定义的方法相比没有明显的差异。为什么需要扩展方法考虑要实现这样的功能:从Redis取出包含多个商品ID的字符串后(每个商品ID使用英文逗号分隔),先对商品ID进行去重(并能够维持元素的顺序),最后再使用英文逗号将各个商品ID进行连接。传统写法:使用Stream写法:假设在Java中能实现扩展方法,并且我们为数组添加了扩展方法toList(将数组变为Li

本文目录

      什么是扩展方法

      扩展方法,就是能够向现有类型直接“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改现有类型。调用扩展方法的时候,与调用在类型中实际定义的方法相比没有明显的差异。

      为什么需要扩展方法

      考虑要实现这样的功能:从 Redis 取出包含多个商品ID的字符串后(每个商品ID使用英文逗号分隔),先对商品ID进行去重(并能够维持元素的顺序),最后再使用英文逗号将各个商品ID进行连接。

      传统写法:

      使用 Stream 写法:

      假设在 Java 中能实现扩展方法,并且我们为数组添加了扩展方法 toList(将数组变为 List),为 List 添加了扩展方法 toSet(将 List 变为 LinkedHashSet),为 Collection 添加了扩展方法 join(将集合中元素的字符串形式使用给定的连接符进行连接),那我们将可以这样写代码:

      相信此刻你已经有了为什么需要扩展方法的答案:

      可以对现有的类库,进行直接增强,而不是使用工具类

      相比使用工具类,使用类型本身的方法写代码更流畅更舒适

      代码更容易阅读,因为是链式调用,而不是用静态方法套娃

      在 Java 中怎么实现扩展方法

      我们先来问问最近大火的 ChatGPT:

      Java中缺失的特性:扩展方法是什么?

      好吧,ChatGPT 认为 Java 里面的扩展方法就是通过工具类提供的静态方法 :)。所以接下来我将介绍一种全新的黑科技:

      Manifold

      准备条件

      Manifold 的原理和 Lombok 是类似的,也是在编译期间通过注解处理器进行处理。所以要在 IDEA 中正确使用 Manifold,需要安装 Manifold IDEA 的插件:

      然后再在项目 pom 的 maven-compiler-plugin 中加入 annotationProcessorPaths:

      如果你的项目中使用了 Lombok,需要把 Lombok 也加入 annotationProcessorPaths:

      编写扩展方法

      JDK 中,String 的 split 方法,使用的是字符串作为参数,即 String[] split(String)。我们现在来为 String 添加一个扩展方法 String[] split(char):按给定的字符进行分割。

      基于 Manifold,编写扩展方法:

      可以发现本质上还是工具类的静态方法,但是有一些要求:

      工具类需要使用 Manifold 的 @Extension 注解

      静态方法中,目标类型的参数,需要使用 @This 注解

      工具类所在的包名,需要以 extensions.目标类型全限定类名 结尾

      —— 用过 C# 的同学应该会会心一笑,这就是模仿的 C# 的扩展方法。

      关于第 3 点,之所以有这个要求,是因为 Manifold 希望能快速找到项目中的扩展方法,避免对项目中所有的类进行注解扫描,提升处理的效率。

      具备了扩展方法的能力,现在我们就可以这样调用了:

      Amazing!而且你可以发现,System.out.println(numStrs.toString()) 打印的居然是数组对象的字符串形式 —— 而不是数组对象的地址。查看反编译后的 App.class,发现是将扩展方法的调用,替换为静态方法调用:

      Java中缺失的特性:扩展方法是什么?

      而数组的 toString 方法,使用的是 Manifold 为数组定义的扩展方法 ManArrayExt.toString(@This Object array):

      Java中缺失的特性:扩展方法是什么?

      [Ljava.lang.String;@511d50c0 什么的,Goodbye,再也不见~

      因为是在编译期将扩展方法的调用替换为静态方法调用,所以使用 Manifold 的扩展方法,即使调用方法的对象是 null 也没有问题,因为处理后的代码是把 null 作为参数传递到对应的静态方法。比如我们对 Collection 进行扩展:

      然后调用的时候:

      java.lang.NullPointerException,Goodbye,再也不见~

      数组扩展方法

      Java中缺失的特性:扩展方法是什么?

      我们看到 List<@Self(true) Object> 这样的写法:@Self 是用来表示被注解的值应该是什么类型,如果是 @Self,即 @Self(false),表示被注解的值和 @This 注解的值是同一个类型;@Self(true) 则表示是数组中元素的类型。

      对于对象数组,我们可以看到 toList 方法返回的就是对应的 List(T 为数组元素的类型):

      Java中缺失的特性:扩展方法是什么?

      但如果是原始类型数组,IDEA 指示的返回值是:

      Java中缺失的特性:扩展方法是什么?

      但是我用的是 Java 啊,擦除法泛型怎么可能拥有 List 这么伟大的功能 —— 所以你只能用原生类型来接收这个返回值 :)

      Java中缺失的特性:扩展方法是什么?

      —— 许个愿,希望 Project Valhalla 早日 GA。

      我们经常在各个项目中看到,大家先把某个对象包装成 Optional,然后进行 filter、map 等。通过 @Self 的类型映射,你可以这样为 Object 加入一个非常实用的办法:

      那么任何对象,都将拥有 asOpt() 方法。

      相比于之前的需要包装一下的不自然:

      你现在可以自然而然的使用 Optional:

      当然,Object 是所有的类的父类,这样做是否合适,还是需要谨慎的思考一下。

      扩展静态方法

      我们都知道 Java9 给集合添加了工厂方法:

      是不是很眼馋?因为如果用的不是 Java9 及以上版本(Java8:直接报我身份证就行),你就得用 Guava 之类的库 —— 然而 ImmutableList.of 用起来终究是比不上 List.of 这样的正统来的自然。

      没关系,Manifold 说:“无所谓,我会出手”。基于 Manifold 扩展静态方法,就是在扩展类的静态方法上,也加上 @Extension:

      然后你就可以欺骗自己已经用上了 Java8 之后的版本 —— 你发任你发,我用 Java8。

      BTW,因为 Object 是所有类的父类,如果你给 Object 添加静态扩展方法,那么意味着你可以在任何地方直接访问到这个静态方法,而不需要 import —— 恭喜你,解锁了 “顶级函数”。

      本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
      作者最新文章
      编程开发 Java
      相关文章 更多
      Java单元测试入门:使用JUnit 5编写第一个测试用例
      Java单元测试入门:使用JUnit 5编写第一个测试用例

      面向初学者的JUnit 5实用入门指南。从测试概念、Maven依赖配置,到手把手编写首个单元测试用例及断言验证,助你掌握Java单元测试的核心流程。

      Java变量未初始化报错解析:局部变量与成员变量默认值差异
      Java变量未初始化报错解析:局部变量与成员变量默认值差异

      深入解析Java中局部变量未初始化编译报错与成员变量自动赋予默认值的机制差异,涵盖JVM内存分配、编译期确定性赋值检查与实际排查修复方案。

      Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat
      Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat

      详细讲解在Java中获取当前系统时间并进行格式化输出的两种核心方案:基于Java 8全新日期时间API的DateTimeFormatter与传统遗留的SimpleDateFormat,包含完整代码示例、线程安全机制对比及生产选型建议。

      Java中final与static final常量的定义及初始化规则
      Java中final与static final常量的定义及初始化规则

      深入解析Java中final变量与static final常量的定义、内存语义、初始化时机及合法赋值路径,涵盖编译期常量优化与实战避坑指南。

      Java抽象方法与接口方法的区别及选型建议
      Java抽象方法与接口方法的区别及选型建议

      深入对比Java中抽象类抽象方法与接口方法的语法演进、设计意图及运行期差异,并提供清晰的架构选型决策流程与实战范例。

      Java实现HTTP请求与JSON解析的完整代码示例
      Java实现HTTP请求与JSON解析的完整代码示例

      本文提供Java标准库HttpClient发起HTTP GET/POST请求并结合Jackson进行JSON数据反序列化与序列化的完整代码示例与工程实践指南。

      Java递归出现StackOverflowError的原因分析及栈空间优化方案
      Java递归出现StackOverflowError的原因分析及栈空间优化方案

      详细分析Java递归调用出现StackOverflowError的原因,结合代码说明线程栈、栈帧和递归深度之间的关系,并介绍终止条件排查、迭代改写、减少栈帧开销以及通过-Xss调整JVM栈空间的方法。

      Java空指针异常(NPE)的代码排查与修复实例
      Java空指针异常(NPE)的代码排查与修复实例

      针对Java中常见的NullPointerException(NPE),本文从堆栈日志定位、典型代码触发场景、具体修复代码对比到防御体系进行系统讲解,提供实用且易上手的排查与修复方案。

      selenium上传文件教程本地文件路径设置方法
      selenium上传文件教程本地文件路径设置方法

      深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

      大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
      大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

      针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

      查看更多
      精品专题 更多
      装机必备
      装机必备

      正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

      Windows
      Windows

      正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

      PDF教程
      PDF教程

      正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

      Mac软件 更多
      讯飞智作 网页版
      讯飞智作 网页版
      Windows/ macOS/ Linux

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      火山引擎 网页版
      火山引擎 网页版
      Windows/ macOS/ Linux

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      Aperty macOS版
      Aperty macOS版
      macOS

      Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

      WINDOWS 更多
      讯飞智作 网页版
      讯飞智作 网页版
      Windows/ macOS/ Linux

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      火山引擎 网页版
      火山引擎 网页版
      Windows/ macOS/ Linux

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      PixTV 网页版
      PixTV 网页版
      Windows

      PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。