【问题标题】:Reusing lambda expressions in Java 8在 Java 8 中重用 lambda 表达式
【发布时间】:2015-04-17 05:17:15
【问题描述】:

Java 8 允许您在不同的上下文中使用相同的 lambda 表达式。考虑下面的代码来证明这一点:

   public class LambdasTypeCheck {
        public static void main(String []args) {
            //Same lambda expression can be used in different contexts.
            Predicate<List<String>> predicate = (l) -> l.add("1");
            Consumer<List<String>>  consumer = (l) -> l.add("1");
        }
    }

lambda 表达式(l) -&gt; l.add("1");在两个地方重复。我怎样才能避免这种重复?我可以重用这个 lambda 表达式的一种方法是,如果有一些接口/类是所有 lambda 表达式的父级,这样我就可以将任何 lambda 表达式分配给这样一个接口/类的引用。

【问题讨论】:

  • 您是否有一个真实的场景,其中相同的 lambda 表达式可以分配给不同的功能接口?你举的例子没有什么意义。 (l) -&gt; l.add("1") 不应用作谓词。
  • 目前我没有。这是否意味着我不应该对此感到好奇?我想知道它是否“可以”完成,而不是它是否“应该”完成。此外,该示例仅用于支持我的问题,而不是我在现实世界中使用的东西。
  • 虽然这两个 lambda 表达式看起来一样,但它们并不相同。他们的目标类型完全不同,所以这是他们的意图。我敢说谓词 lambda 很糟糕,因为它有副作用。为了保持引用透明度,它应该是l::contains

标签: lambda java-8 reusability


【解决方案1】:

使用相同的代码在相同的方法中实现两个不同的接口的机会,让我们面对现实吧,几乎为零。但即便如此,当您遇到重复代码时,您也可以做您可能总是做的事情:创建一个新方法/类。

public class LambdasTypeCheck {
  public static void main(String []args) {
    Predicate<List<String>> predicate = LambdasTypeCheck::addOne;
    Consumer<List<String>>  consumer = LambdasTypeCheck::addOne;
  }

  public static boolean addOne(List<String> list) {
    return list.add("1");
  }
}

当然,当您想要捕获值时,这是行不通的:

String one = "1";
Predicate<List<String>> predicate = (l) -> l.add(one);
Consumer<List<String>>  consumer = (l) -> l.add(one);

这里你必须使用 lambda 表达式,你只能求助于@Holger 建议的解决方案。但是话又说回来:这(方法中的代码重复)是非常非常不可能的情况:)

【讨论】:

    【解决方案2】:

    您没有定义您担心的是哪种“重复”。

    如果是代码重复(或者说,担心故意应该相同的表达式之间可能出现不一致)困扰你,你可以使用

    Predicate<List<String>> predicate = (l) -> l.add("1");
    Consumer<List<String>>  consumer = predicate::test;
    

    避免它。

    如果您希望 lambda 表达式真正由同一个实例表示,您可以创建一个组合 interface

    interface PredicateAndConsumer<T> extends Predicate<T>, Consumer<T> {
        public default void accept(T t) { test(t); }
    }
    

     

    PredicateAndConsumer<List<String>> pAndC = (l) -> l.add("1");
    Predicate<List<String>> predicate = pAndC;
    Consumer<List<String>>  consumer = pAndC;
    

    因此,如您所见,您可以在需要Predicate&lt;List&lt;String&gt;&gt;Consumer&lt;List&lt;String&gt;&gt; 的两种情况下使用pAndC

    但是,这样做几乎没有什么好处。在这种特殊情况下,我们可以放心地假设,对于大多数 JRE,引入另一个 interface 的开销高于通过一个 lambda 表达式实现它所节省的开销。


    您也可以考虑“Is method reference caching a good idea in Java 8?”的答案。总而言之,您的示例表达式不捕获值,因此将在 Oracle 的参考实现中作为单例实现(并且可能在所有替代实现中也是如此)。所以这里我们讨论的是在运行时环境中是否创建了一个或两个不可变常量……

    【讨论】:

    猜你喜欢
    • 2017-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-25
    • 2015-06-01
    • 2015-07-05
    相关资源
    最近更新 更多