如何在嵌套方法中使用方法引用操作符?实现代码风格统一
嘿,这个问题问得很到位——很多人刚用Lambda和方法引用的时候都想这么写,可惜Java原生语法并不支持A::getB::getC::getD::isE这种链式方法引用,不过我们有几种办法能达到你想要的代码简洁性和一致性,来看看:
解决方案一:原生Java函数组合(无依赖)
Java的Function接口本身就提供了andThen()方法,可以把多个方法引用串起来,最终转换成一个Predicate给filter用。这种方案完全依赖Java原生API,不需要额外引入库,兼容性最好:
// 先把每个方法引用拆成独立的Function,可读性更好 Function<A, B> getB = A::getB; Function<B, C> getC = B::getC; Function<C, D> getD = C::getD; Function<D, Boolean> isE = D::isE; // 组合成一个从A到Boolean的Function,再转成Predicate Predicate<A> hasValidE = getB.andThen(getC).andThen(getD).andThen(isE)::apply; // 直接用在filter里 yourStream.filter(hasValidE);
如果觉得拆成变量太啰嗦,也可以一行搞定(注意强制转型第一个方法引用,帮编译器明确类型):
yourStream.filter( ((Function<A, B>) A::getB) .andThen(B::getC) .andThen(C::getD) .andThen(D::isE) ::apply );
解决方案二:用第三方库简化写法
如果你的项目可以引入第三方工具库,比如Vavr(原Javaslang)或者jOOL,它们对函数式编程的支持更友好,能让代码更紧凑:
Vavr 示例
Vavr的Function1支持更流畅的链式组合:
import io.vavr.Function1; yourStream.filter( Function1.of(A::getB) .andThen(B::getC) .andThen(C::getD) .andThen(D::isE) .test() );
jOOL 示例
jOOL提供了类似你想要的占位符写法,用$代替参数名,视觉上更简洁:
import static org.jooq.lambda.tuple.Tuple.$; yourStream.filter($ -> $.getB().getC().getD().isE());
解决方案三:自定义占位符小技巧(伪_.xxx写法)
如果你不想引入依赖,又想接近_.xxx的写法,可以自己定义一个静态占位符方法(本质还是Lambda,但视觉上更符合你的预期):
// 定义一个工具类 public class LambdaUtils { @SuppressWarnings("unchecked") public static <T> T _() { throw new UnsupportedOperationException("这只是Lambda占位符,不会实际执行"); } } // 静态导入后使用 import static com.yourpackage.LambdaUtils._; yourStream.filter($ -> $._().getB().getC().getD().isE());
注意:这个_()方法永远不会被实际调用,只是用来让编译器通过类型检查,写法上更贴近你想要的风格。
为什么原生Java不支持链式方法引用?
简单来说,Java的方法引用语法是针对单个方法的:A::getB会被编译成一个Function<A, B>实例,但::getC需要的是一个接收B类型的方法引用,Java编译器无法自动把前一个Function的输出和后一个方法引用的输入关联起来,所以链式写法A::getB::getC在语法上是不合法的。
内容的提问来源于stack exchange,提问作者sampath.xyz
相关产品推荐
相关产品推荐

