Как я могу написать анонимную функцию на Java?

88

Это вообще возможно?

Аарона
источник
6
Обратите внимание, что теперь это возможно в Java 8 - см. Ответ Марка Роттевела о лямбда-выражениях ниже.
Джозайя Йодер,

Ответы:

81

если вы имеете в виду анонимную функцию и используете версию Java до Java 8, то одним словом, нет. ( Прочтите о лямбда-выражениях, если вы используете Java 8+ )

Однако вы можете реализовать интерфейс с такой функцией:

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

и вы можете использовать это с внутренними классами, чтобы получить почти анонимную функцию :)

Крис
источник
6
Еще нет. В Java 7 это станет возможным: stackoverflow.com/questions/233579/closures-in-java-7
Илья Бояндин,
2
Тем временем, пока вы ждете JDK7, анонимные методы можно эмулировать в объектно-
ориентированном
1
closured не попал в Java 7.
Thorbjørn Ravn 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
@BalusC: добавлена ​​ссылка на вопрос "как они используются"
polygenelubricants
@BalusC: stackoverflow недавно добавил Linkedбоковую панель, поэтому я изо всех сил стараюсь ее использовать.
полимерные смазки
12

С введением лямбда-выражения в Java 8 теперь у вас могут быть анонимные методы.

Скажем, у меня есть класс, Alphaи я хочу отфильтровать Alphas по определенному условию. Для этого вы можете использовать файл Predicate<Alpha>. Это функциональный интерфейс, который имеет метод, testкоторый принимает Alphaи возвращает boolean.

Предполагая, что метод фильтра имеет такую ​​подпись:

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

Со старым решением анонимного класса вам понадобится что-то вроде:

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

С помощью лямбда-выражений Java 8 вы можете:

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

Для получения более подробной информации см. Руководство по лямбда-выражениям.

Марк Роттевил
источник
2
Ссылки на методы также полезны. например, sort (String :: compareToIgnoreCase) docs.oracle.com/javase/tutorial/java/javaOO/…
Джозия Йодер,
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а не curв printметоде. Скажите НЕТ "неявному final" захвату локальных жителей? )

Том Хотин - tackline
источник
nodeдолжно быть объявлено finalздесь.
BalusC
@BalusC Хороший улов. На самом деле моей ошибкой было не использовать cur.
Том Хотин - tackline
@Tom: +1 хорошая техника! Используется ли он где-нибудь на практике? Какое название для этого конкретного шаблона?
Полигенные смазки
@polygenelubricants Насколько я знаю. Стоит целый лишний объект! (И класс.) Во многом то же самое относилось и к идиоме двойной скобки. Правильно мыслящие люди, похоже, не возражают против идиомы «Казнить».
Том Хотин - tackline
@polygenelubricants На самом деле мне не кажется, что много (самодостаточных) рекурсивных алгоритмов. В частности, те, которые не являются хвостовыми рекурсивными (или которые легко сделать так) и не могут быть реализованы путем вызова общедоступного метода (обратите внимание на немного несущественное, "Node" +чтобы сделать второй метод необходимым). / У меня нет имени. Возможно, я мог бы создать вопрос для именования "опроса" (CW) и забыть его.
Том Хотин - tackline
1

Да, если вы используете последнюю версию java, то есть версию 8. 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.

  • Круглые скобки, которые содержат аргументы конструктора, как и обычное выражение создания экземпляра класса. Примечание. Когда вы реализуете интерфейс, конструктора нет, поэтому вы используете пустую пару круглых скобок, как в этом примере.

  • Тело, которое является телом объявления класса. В частности, в теле объявления методов разрешены, а операторы - нет.

мамаша
источник