其他
Java 缺失的特性:扩展方法
什么是扩展方法
为什么需要扩展方法
// "123,456,123,789"
String str = redisService.get(someKey)
String itemIdStrs = String.join(",", new LinkedHashSet<>(Arrays.asList(str.split(","))));
String itemIdStrs = Arrays.stream(str.split(",")).distinct().collect(Collectors.joining(","));
String itemIdStrs = str.split(",").toList().toSet().join(",");
可以对现有的类库,进行直接增强,而不是使用工具类
相比使用工具类,使用类型本身的方法写代码更流畅更舒适
代码更容易阅读,因为是链式调用,而不是用静态方法套娃
在 Java 中怎么实现扩展方法
好吧,ChatGPT 认为 Java 里面的扩展方法就是通过工具类提供的静态方法 :)。所以接下来我将介绍一种全新的黑科技:
Manifold(https://github.com/manifold-systems/manifold)
准备条件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<properties>
<manifold.version>2022.1.35</manifold.version>
</properties>
<dependencies>
<dependency>
<groupId>systems.manifold</groupId>
<artifactId>manifold-ext</artifactId>
<version>${manifold.version}</version>
</dependency>
...
</dependencies>
<!--Add the -Xplugin:Manifold argument for the javac compiler-->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-Xplugin:Manifold no-bootstrap</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>systems.manifold</groupId>
<artifactId>manifold-ext</artifactId>
<version>${manifold.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>systems.manifold</groupId>
<artifactId>manifold-ext</artifactId>
<version>${manifold.version}</version>
</path>
</annotationProcessorPaths>
编写扩展方法
package com.alibaba.zhiye.extensions.java.lang.String;
import manifold.ext.rt.api.Extension;
import manifold.ext.rt.api.This;
import org.apache.commons.lang3.StringUtils;
/**
* String 的扩展方法
*/
@Extension
public final class StringExt {
public static String[] split(@This String str, char separator) {
return StringUtils.split(str, separator);
}
}
可以发现本质上还是工具类的静态方法,但是有一些要求:
工具类需要使用 Manifold 的 @Extension 注解
静态方法中,目标类型的参数,需要使用 @This 注解
工具类所在的包名,需要以 extensions.目标类型全限定类名 结尾
—— 用过 C# 的同学应该会会心一笑,这就是模仿的 C# 的扩展方法。
[Ljava.lang.String;@511d50c0 什么的,Goodbye,再也不见~
package com.alibaba.zhiye.extensions.java.util.Collection;
import manifold.ext.rt.api.Extension;
import manifold.ext.rt.api.This;
import java.util.Collection;
/**
* Collection 的扩展方法
*/
@Extension
public final class CollectionExt {
public static boolean isNullOrEmpty(@This Collection<?> coll) {
return coll == null || coll.isEmpty();
}
}
List<String> list = getSomeNullableList();
// list 如果为 null 会进入 if 块,而不会触发空指针异常
if (list.isNullOrEmpty()) {
// TODO
}
数组扩展方法
package com.alibaba.zhiye.extensions.java.lang.Object;
import manifold.ext.rt.api.Extension;
import manifold.ext.rt.api.Self;
import manifold.ext.rt.api.This;
import java.util.Optional;
/**
* Object 的扩展方法
*/
@Extension
public final class ObjectExt {
public static Optional<@Self Object> asOpt(@This Object obj) {
return Optional.ofNullable(obj);
}
}
Optional.ofNullable(someObj).filter(someFilter).map(someMapper).orElseGet(someSupplier);
someObj.asOpt().filter(someFilter).map(someMapper).orElseGet(someSupplier);
扩展静态方法
List<String> list = List.of("a", "b", "c");
Set<String> set = Set.of("a", "b", "c");
Map<String, Integer> map = Map.of("a", 1, "b", 2, "c", 3);
package com.alibaba.aladdin.app.extensions.java.util.List;
import manifold.ext.rt.api.Extension;
import manifold.ext.rt.api.This;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* List 扩展方法
*/
@Extension
public final class ListExt {
/**
* 返回只包含一个元素的不可变 List
*/
@Extension
public static <E> List<E> of(E element) {
return Collections.singletonList(element);
}
/**
* 返回包含多个元素的不可变 List
*/
@Extension
@SafeVarargs
public static <E> List<E> of(E... elements) {
return Collections.unmodifiableList(Arrays.asList(elements));
}
}
建议
关于 Manifold
谨慎添加扩展方法
public static boolean isValidParam(String str) {
return StringUtils.isNotBlank(str) && !"null".equalsIgnoreCase(str);
}