(ab)使用Java 8 FunctionalInterfaces作为本地方法

如果您使用Scala或Ceylon甚至JavaScript等更高级的语言进行编程,则“嵌套函数”“本地函数”是您非常常见的习惯用法。 例如,您将编写诸如fibonacci函数之类的东西:

def f() = {
  def g() = "a string!"
  g() + "– says g"
}

f()函数包含一个嵌套的g()函数,该函数对于外部f()函数的作用域是局部的。

在Java中,无法创建这样的局部函数,但是您可以将lambda表达式分配给局部变量,然后使用它。

上面的示例可以转换为以下Java代码:

String f() {
    Supplier<String> g = () -> "a string!";
    return g.get() + "- says g";
}

尽管这个例子很简单,但测试一个更有用的用例。 例如,请考虑以下jOOλ单元测试 ,它检查是否Stream.close()的语义正确跨越各种jOOλ实施Seq方法,即两股合并为一个:

@Test
public void testCloseCombineTwoSeqs() {
    Consumer<BiFunction<Stream<Integer>, Stream<Integer>, Seq<?>>> test = f -> {
        AtomicBoolean closed1 = new AtomicBoolean();
        AtomicBoolean closed2 = new AtomicBoolean();
        
        Stream s1 = Stream.of(1, 2).onClose(() -> closed1.set(true));
        Stream s2 = Stream.of(3).onClose(() -> closed2.set(true));
        
        try (Seq s3 = f.apply(s1, s2)) {
            s3.collect(Collectors.toList());
        }

        assertTrue(closed1.get());
        assertTrue(closed2.get());
    };
    
    test.accept((s1, s2) -> seq(s1).concat(s2));
    test.accept((s1, s2) -> seq(s1).crossJoin(s2));
    test.accept((s1, s2) -> seq(s1).innerJoin(s2, (a, b) -> true));
    test.accept((s1, s2) -> seq(s1).leftOuterJoin(s2, (a, b) -> true));
    test.accept((s1, s2) -> seq(s1).rightOuterJoin(s2, (a, b) -> true));
}

局部函数是test ,它接受两个Stream<Integer>参数,产生一个Seq<?>结果。

为什么不只写私有方法呢?

当然,这也可以通过私有方法(经典的Java风格)解决。 但是有时候,使用局部作用域会更加方便,因为测试Consumer (局部功能)无法逃脱该单个单元测试的作用域。 仅应在此单一方法内使用。

另一种更经典的Java方法是定义一个本地类,然后将函数放入其中。 但是这种解决方案更加精益。

但是,一个缺点是,在Java中,以这种方式实现递归要困难得多。

翻译自: https://www.javacodegeeks.com/2016/02/abusing-java-8-functionalinterfaces-local-methods.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值