Java로 익명 함수를 작성하려면 어떻게해야합니까?


답변:


81

익명 기능을 의미하고 Java 8 이전의 Java 버전을 사용하는 경우 한마디로 아닙니다. ( 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
Ilya Boyandin

2
JDK7을 기다리는 동안 한편, 익명 방법을 사용하여 OO 컨텍스트에서 에뮬레이트 할 수 en.wikipedia.org/wiki/Command_pattern
gpampara을

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@OverridetoString()메소드 의 인스턴스를 만드는 방법을 보여줍니다 .

또한보십시오


익명 내부 클래스는 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에 람다식이 도입됨에 따라 이제 익명 메서드를 사용할 수 있습니다.

클래스가 Alpha있고 Alpha특정 조건에서 s 를 필터링하고 싶습니다 . 이를 위해 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);

자세한 내용은 Lambda 표현식 자습서를 참조하십시오.


2
메서드 참조도 유용합니다. 예를 들어, 정렬 (문자열 :: compareToIgnoreCase) docs.oracle.com/javase/tutorial/java/javaOO/...
요시야 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방법. 말 NO "를 암시 적으로 캡처에 final"지역 주민을? )


nodefinal여기서 선언해야합니다 .
BalusC 2010 년

@BalusC 좋은 캐치. 사실 내 실수는 cur.
Tom Hawtin-tackline

@Tom : +1 멋진 기술! 실제로 어디에서나 실제로 사용됩니까? 이 특정 패턴에 대한 이름이 있습니까?
polygenelubricants 2010 년

@polygenelubricants 내가 아는 한 멀지 않습니다. 전체 추가 개체 비용! (그리고 클래스.) 이중 중괄호 관용구도 마찬가지였습니다. 옳은 생각을하는 사람들은 Execute Around 관용구를 신경 쓰지 않는 것 같습니다.
Tom Hawtin-tackline

@polygenelubricants 사실 나는 많은 (자체 포함) 재귀 알고리즘을 보이지 않습니다. 특히 꼬리 재귀 적이 지 않고 (또는 쉽게 만들 수 있고) public 메서드를 호출하여 구현할 수없는 경우 ( "Node" +두 번째 메서드를 필요로하는 것과 약간 관련 이 없음). / 이름이 없어요. 아마도 CW (nameming "poll") 질문을 만들어 망각에 빠뜨릴 수있을 것입니다.
Tom Hawtin-tackline

1

예, 버전 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 인터페이스를 구현합니다.

  • 일반 클래스 인스턴스 생성 표현식과 마찬가지로 생성자에 대한 인수를 포함하는 괄호. 참고 : 인터페이스를 구현할 때 생성자가 없으므로이 예제에서와 같이 빈 괄호 쌍을 사용합니다.

  • 클래스 선언 본문 인 본문입니다. 보다 구체적으로 본문에서 메서드 선언은 허용되지만 문은 허용되지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.