【问题标题】:How can I write an anonymous function in Java?如何在 Java 中编写匿名函数?
【发布时间】:2010-05-02 23:31:32
【问题描述】:

有可能吗?

【问题讨论】:

  • 请注意,现在这在 Java 8 中是可能的——请参阅下面 Mark Rotteveel 关于 Lambda 表达式的答案。

标签: java anonymous-function


【解决方案1】:

如果您指的是匿名函数,并且使用的是 Java 8 之前的 Java 版本,那么简而言之,不。 (Read about lambda expressions if you use Java 8+)

但是,您可以使用如下函数实现接口:

Comparator<String> c = new Comparator<String>() {
    int compare(String s, String s2) { ... }
};

你可以将它与内部类一起使用来获得一个几乎匿名的函数:)

【讨论】:

【解决方案2】:

这是一个匿名内部类的示例。

System.out.println(new Object() {
    @Override public String toString() {
        return "Hello world!";
    }
}); // prints "Hello world!"

这并不是很有用,但它展示了如何创建一个匿名内部类的实例,该类使用 extends Object@OverridetoString() 方法。

另见


当您需要实现一个interface 时,匿名内部类非常方便,它可能不是高度可重用的(因此不值得重构为它自己的命名类)。一个有启发性的示例是使用自定义 java.util.Comparator&lt;T&gt; 进行排序。

这是一个示例,说明如何根据 String.length()String[] 进行排序。

import java.util.*;
//...

String[] arr = { "xxx", "cd", "ab", "z" };
Arrays.sort(arr, new Comparator<String>() {
    @Override public int compare(String s1, String s2) {
        return s1.length() - s2.length();
    }           
});
System.out.println(Arrays.toString(arr));
// prints "[z, cd, ab, xxx]"

注意这里使用的减法比较技巧。应该说,这种技术总体上是被打破的:它只有在你能保证它不会溢出的情况下才适用(String长度就是这种情况)。

另见

【讨论】:

  • 在普通 Swing 应用程序中,大多数其他事件都可以在 EventListener(子)实现中找到。
  • @BalusC:添加了问题“它们是如何使用的”的链接
  • @BalusC:stackoverflow 最近添加了Linked 侧边栏,所以我正在尽力利用它。
【解决方案3】:

随着在 Java 8 中引入 lambda 表达式,您现在可以拥有匿名方法。

假设我有一个班级Alpha,我想在特定条件下过滤Alphas。为此,您可以使用Predicate&lt;Alpha&gt;。这是一个函数式接口,它有一个方法 test,它接受一个 Alpha 并返回一个 boolean

假设过滤器方法有这个签名:

List<Alpha> filter(Predicate<Alpha> filterPredicate)

使用旧的匿名类解决方案,您需要:

filter(new Predicate<Alpha>() {
   boolean test(Alpha alpha) {
      return alpha.centauri > 1;
   }
});

使用 Java 8 lambda,您可以:

filter(alpha -> alpha.centauri > 1);

有关更多详细信息,请参阅Lambda Expressions tutorial

【讨论】:

【解决方案4】:

实现或扩展现有类型接口的匿名内部类已在其他答案中完成,但值得注意的是可以实现多种方法(例如,通常使用 JavaBean 样式的事件)。

一个公认的特点是,虽然匿名内部类没有名称,但它们确实有一个类型。可以将新方法添加到接口中。这些方法只能在有限的情况下调用。主要是直接在new 表达式本身和类内(包括实例初始化程序)。它可能会让初学者感到困惑,但它对于递归来说可能是“有趣的”。

private static String pretty(Node node) {
    return "Node: " + new Object() {
        String print(Node cur) {
            return cur.isTerminal() ?
                cur.name() :
                ("("+print(cur.left())+":"+print(cur.right())+")");
        }
    }.print(node);
}

(我最初是在 print 方法中使用 node 而不是 cur 编写的。对捕获“隐式 final”本地人说不?

【讨论】:

  • node 应在此处声明为final
  • @BalusC 不错的收获。其实我的错误是没有使用cur
  • @Tom:+1 不错的技术!它实际上在实践中的任何地方都使用过吗?这个特定模式有什么名字吗?
  • @polygenelubricants 据我所知没有。花费一个额外的对象! (还有一个类。)双括号习语也是如此。思维正确的人似乎并不介意 Execute Around 成语。
  • @polygenelubricants 实际上我似乎没有那么多(自包含)递归算法。特别是那些不是尾递归的(或很容易做到的)并且不能通过调用公共方法来实现的(注意稍微不相关的"Node" +,使第二种方法成为必要)。 / 我没有名字。也许我可以创建一个命名“民意调查”(CW)问题,然后将其否决。
【解决方案5】:

是的,如果您使用的是最新的 Java 版本 8。Java8 可以定义以前版本中不可能的匿名函数。

让我们以java docs 为例,了解我们如何声明匿名函数、类

以下示例 HelloWorldAnonymousClasses 使用匿名 局部变量的初始化语句中的类 frenchGreeting 和 spanishGreeting,但使用本地类 变量englishGreeting的初始化:

public class HelloWorldAnonymousClasses {

    interface HelloWorld {
        public void greet();
        public void greetSomeone(String someone);
    }

    public void sayHello() {

        class EnglishGreeting implements HelloWorld {
            String name = "world";
            public void greet() {
                greetSomeone("world");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hello " + name);
            }
        }

        HelloWorld englishGreeting = new EnglishGreeting();

        HelloWorld frenchGreeting = new HelloWorld() {
            String name = "tout le monde";
            public void greet() {
                greetSomeone("tout le monde");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Salut " + name);
            }
        };

        HelloWorld spanishGreeting = new HelloWorld() {
            String name = "mundo";
            public void greet() {
                greetSomeone("mundo");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hola, " + name);
            }
        };
        englishGreeting.greet();
        frenchGreeting.greetSomeone("Fred");
        spanishGreeting.greet();
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp =
            new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }            
}

匿名类的语法

考虑 frenchGreeting 对象的实例化:

    HelloWorld frenchGreeting = new HelloWorld() {
        String name = "tout le monde";
        public void greet() {
            greetSomeone("tout le monde");
        }
        public void greetSomeone(String someone) {
            name = someone;
            System.out.println("Salut " + name);
        }
    };

匿名类表达式包含以下内容:

  • new 运算符
  • 要实现的接口或要扩展的类的名称。在这个 例如,匿名类正在实现接口 你好世界。

  • 包含构造函数参数的括号,就像 普通类实例创建表达式。注意:当你实施 一个接口,没有构造函数,所以你使用一对空的 括号,如本例所示。

  • 一个主体,它是一个类声明主体。更具体地说,在 body,方法声明是允许的,但语句是不允许的。

【讨论】:

    【解决方案6】:

    您还可以使用ConsumerBiConsumer 类型来确定您需要多少参数。 Consumer 接受一个参数,BiConsumer 接受两个参数。

    public void myMethod() {
      // you can declare it here
      Consumer<String> myAnonymousMethod = s -> {
        System.out.println(s);
      };
    
      // you can call it here
      muAnonymousMethod.apply("Hello World");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-02
      • 1970-01-01
      • 1970-01-01
      • 2019-12-25
      • 1970-01-01
      • 2012-10-23
      相关资源
      最近更新 更多