java8函数接口处理回调

Posted

技术标签:

【中文标题】java8函数接口处理回调【英文标题】:java8 functional interface to handle the callback 【发布时间】:2018-01-11 23:32:11 【问题描述】:

我有一个通用的私有方法,它执行常见任务并被其他方法使用。泛型方法具有ifelse 条件以支持调用的其他方法。示例:

private void myGenericMethod(String name, int age)
  common task1;
  common task2;
  if(name!= null && name.length > 0)
     specific task 1;
     specific task 2;
   else
     specific task 3;
     specific task 4;
  
  if(age > 18)
     specific task 1`;
     specific task 2`;
  

我想使用 Java 8 lambda,并且我使用 invoke 方法创建了一个名为 Invoker 的功能接口。

public interface Invoker
  public void invoke()

现在我的通用方法看起来像这样,公共方法适当地处理调用函数回调:

private void myGenericMethod(Invoker invoker)
  common task1;
  common task2;
  invoker.invoke();
  

JDK中有没有我可以使用的功能接口,而不是自己创建这个接口?

【问题讨论】:

您可以查看java.util.function 包并选择适合您要求的包。我不能推荐一个,因为我不知道你的具体任务是否有争论(或更多)等等...... 【参考方案1】:

java.util.function 不包含带有不需要任何参数并返回void 的方法的功能接口。但是你可以改用Runnable接口。

private void myGenericMethod(Runnable runnable)
    common task1;
    common task2;
    //consider checking if runnable != null to avoid NPE
    runnable.run();
  

然后调用看起来很简单:

myGenericMethod(() -> 
    //do something fancy
    System.out.println("Hello, world!");
);

其他选项

还有其他你可能感兴趣的功能接口,例如:

Supplier<T> 如果你想在不传递任何参数的情况下返回 T 的值 Function<T,R> 如果要传递 T 的值并返回 R 的值 Consumer<T> 如果您想将值 T 作为参数传递并返回 void

为什么Runnable接口没有替代品?

Runnable 接口用于不返回任何内容且不期望任何参数的lambda 对许多程序员来说可能听起来有争议。 Runnable 是为在单独的线程中运行代码而发明的,许多程序员将此类标识为多线程。甚至documentation 说:

Runnable 接口应该由其实例打算由线程执行的任何类实现。

有人already asked similar question 2 年前,如果你看看this comment 和Brian Goetz's 对它的反应,你就会明白Java 语言设计者得出的结论是没有必要创建另一个模仿的功能接口Runnable 接口的实现。

【讨论】:

Runnable 旨在封装可以异步完成的工作。在这种情况下使用它是令人困惑的[需要引用]。如果意图被其他开发人员误解,可能会导致严重的问题。有人建议创建自己的界面,称为 OperationExecutable 或类似的名称。 如果您使用“调用”术语,我建议改用接口名称 Invokable,以符合命名约定。 我不想使用Runnable 的原因是当他们看到 Runnable 并造成混乱时,它会引起共同开发人员的眉毛。我会坚持使用 Invokable。但令我惊讶的是Java8没有这样的接口 是的,java.util.function 中应该有一个。在这种情况下,最好使用您的自定义选项。 @zilcuanu Brian Goetz 解释了为什么这里没有 Runnable 接口的替代品 - ***.com/questions/27973294/… 引用:“我确信 Runnable 的存在是 Java 设计人员认为他们没有'不需要添加另一个功能接口”,Brian 证实了这一点。【参考方案2】:

也可以使用Consumer<Void>。它可能看起来像这样

public void init(Consumer<Void> callback) 
    callback.accept(null);


init((Void) -> done());

【讨论】:

【参考方案3】:

我建议使用 Consumer 作为回调接口。与 javascript 语言相比,回调与范围绑定。因此,如果您使用 Consumer 接口,则可以将范围作为参数传递给函数。 例如:

public void startTracer(String tracerName, Event boundEvent) 
    executeOnTracer(tracer -> tracer.startTracer(tracerName, boundEvent));

...
private void executeOnTracer(Consumer<Tracer> callback) 
    TracerController tracer = null;
    if (isTracerActive()) 
        tracer = getTracer();
    
    Optional.ofNullable(tracer).ifPresent(callback::accept);

【讨论】:

以上是关于java8函数接口处理回调的主要内容,如果未能解决你的问题,请参考以下文章

Java8中的函数式接口SupplierConsumerBiConsumer详解

Java8中的函数式接口SupplierConsumerBiConsumer详解

java进阶|基于java8的函数式接口做一些数据处理

Java8学习笔记

玩转Java8的 Stream 之函数式接口

玩转Java8Stream之函数式接口