如何用Java编写匿名函数?


Answers:


81

如果您的意思是匿名函数,并且在Java 8之前使用的是Java版本,那么总而言之,不是。(如果您使用Java 8+,请阅读有关lambda表达式的信息

但是,您可以使用以下功能实现接口:

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

并且您可以将其与内部类一起使用以获取几乎匿名的功能:)


6
还没。在Java 7
中将

2
同时,在等待JDK7的同时,可以使用en.wikipedia.org/wiki/Command_pattern
gpampara,2010年

1
封闭并没有使它进入Java7。
ThorbjørnRavn Andersen

5
我想你应该修改你的答案,因为我们有与Java 8匿名函数
Node.js的

45

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

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

这并不像它是非常有用的,但它显示了如何创建一个匿名内部类的一个实例extends Object@Override它的toString()方法。

也可以看看


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

这是一个如何String[]基于排序的示例String.length()

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长度是这样)。

也可以看看


5
EventListener在平均的Swing应用程序中,大多数其他事件可以作为(子)实现找到。
BalusC,2010年

@BalusC:添加链接问题:“如何使用它们”
polygenelubricants

@BalusC:stackoverflow最近添加了Linked侧边栏,因此我正在尽力利用它。
polygenelubricants 2010年

12

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

假设我有一个课程,Alpha并且想Alpha在特定条件下过滤。为此,您可以使用Predicate<Alpha>。这是一个功能性接口,具有一个test接受anAlpha并返回an的方法boolean

假设filter方法具有以下签名:

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教程。


2
方法引用也很有用。例如sort(String :: compareToIgnoreCase) docs.oracle.com/javase/tutorial/java/javaOO/…–
Josiah Yoder

9

尽管值得注意的是可以实现多种方法(例如,通常使用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);
}

(我最初写这个使用node,而不是curprint方法说不捕捉“含蓄final”本地人?


node应该在final这里声明。
BalusC,2010年

@BalusC不错的收获。实际上我的错误是不使用cur
汤姆·霍顿

@汤姆:+1好技术!实际在任何地方都可以使用吗?这个特定模式有什么名字吗?
多基因

@polygenelubricants据我所知。花费一个额外的对象!(和一堂课。)双括号成语大同小异。正确思考的人似乎并不介意Execute Perform惯用语。
汤姆·霍顿

@polygenelubricants实际上,我似乎没有很多(独立的)递归算法。特别是那些不是尾递归的(或者很容易做到)并且不能通过调用public方法来实现的(请注意"Node" +,使第二个方法成为必需的方法与之无关)。/我没有名字。也许我可以创建一个命名“民意测验”(CW)问题,并将其淘汰。
汤姆·霍顿

1

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

让我们以Java文档为例,了解如何声明匿名函数,类

以下示例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运营商
  • 要实现的接口名称或要扩展的类的名称。在此示例中,匿名类正在实现接口HelloWorld。

  • 括号中包含构造函数的参数,就像普通的类实例创建表达式一样。注意:在实现接口时,没有构造函数,因此,如本例所示,使用一对空括号。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.