【问题标题】:Calling a method in ExecuterService using double colon (::) [duplicate]使用双冒号 (::) 在 ExecutorService 中调用方法 [重复]
【发布时间】:2020-04-01 12:01:27
【问题描述】:

我有一个类分别包含 2 个静态和非静态方法,根据我的有限知识,提交方法直接接受可运行的、可调用的实例或通过 lamba 表达式。

今天我知道,我们甚至可以直接调用或触发静态和非静态方法,使用java 8中添加的双冒号。

我只是想知道这是如何工作的,我的类中没有 run 方法,它没有实现 runnable 甚至我没有使用 lamba?

使用 :: 是一种好习惯,还是应该传递可运行或可调用实例。

还有其他方法可以在 submit() 中调用方法而不是传递实例吗?

Class A {

public static void printSomething(){
System.out.println("Staitc Method");
}

public void print()
{
System.out.println("Non-Staitc Method");
}

}

psvm()
{
A a = new A():
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(A::printSomething);  //Expected is runnable or callable task
es.submit(a::print);
}

【问题讨论】:

  • 你可以es.submit(() -> { // code/invoke a void method here });run 方法调用您的 print 方法。
  • @Naman 这是有效的 lambda 表达式,间接它是 run 方法,但 :: 是如何工作的?
  • 链接的问题很好地回答了不同答案中的各种示例。

标签: java multithreading java-8 concurrency executorservice


【解决方案1】:

A::printSomething 称为方法引用。当您在需要类似 Runnable 或 Callable 接口的地方使用方法引用时,Java 会自动创建调用该方法的该接口的实现。

也就是说,

es.submit(A::printSomething);

行为与

相同
es.submit(new Runnable() {
    public void run() {
        A.printSomething();
    }
});

但更易于阅读,并且不会在您使用它的任何地方创建一个新类,或者每次调用它时都创建一个新对象实例。

您可以在

中阅读有关方法引用的更多信息

实现相同目的的另一种方法是使用 lambda 表达式,例如:

es.submit(() -> A.printSomething());

【讨论】:

    【解决方案2】:

    由于Runnablefunctional interface,因此即使方法名称不匹配,您也可以使用适合它的 lambda 表达式或方法引用。因此,任何无参数的 void 方法都可以用作Runnable

    Runnable r1 = () -> a.printSomething();
    Runnable r2 = A::printSomething();  // Method reference, short-hand
    Runnable r3 = () -> A.printSomething(); // Same as r2, but as explicit lambda expression
    

    【讨论】:

    • 是的,关键词是“功能接口”1+
    • 每次对不同的方法使用方法参考是一个好习惯吗?
    • @Shelly 我想这取决于你问谁。对于无参数方法并没有太大区别,但是当方法有参数时,使用显式版本(a, b) -> foo(a, b)this::foo 会变得更加清晰,例如在使用 Streams 时。
    • @Kayaman 谢谢人
    【解决方案3】:

    即使类没有实现void run() 方法,方法引用仍然有效的原因是,对于函数式接口分配而言,重要的是方法签名而不是方法名称。

    AprintSomething 的方法签名与 Runnablerun 匹配,因此它可以工作。请注意,这只适用于功能接口(即只有一种方法的接口,即没有默认实现的方法方法)。

    这是好的做法吗?这是风格问题,但使用方法引用绝对不是坏习惯,而且它们也比left -> right lambdas 更简洁。

    我建议你自己尝试一下,这样你就清楚规则了。

    public class FunctionalInterfaceDemo {
    
      public static class SimpleClass {
        public static void doItStatic() {
        }
    
        public void doItNonStatic() {
        }
      }
    
      interface MyOwnFunctionalInterface {
        void methodA();
      }
    
      interface NotAFunctionalInterface {
        void methodA();
    
        void methodB();
      }
    
      interface AlsoNotAFunctionalInterface {
        default void methodA() {
        }
      }
    
    
      public static void main(String[] args) {
        MyOwnFunctionalInterface compiles = SimpleClass::doItStatic;
        MyOwnFunctionalInterface alsoCompiles = new SimpleClass()::doItNonStatic;
        NotAFunctionalInterface doesNotCompile = SimpleClass::doItStatic;
        AlsoNotAFunctionalInterface alsoDoesNotCompile = SimpleClass::doItStatic;
      }
    

    }

    【讨论】:

    • 你的例子真的很有帮助
    猜你喜欢
    • 2012-06-18
    • 2011-04-14
    • 2013-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多