development

Java에서 함수를 매개 변수로 전달하는 방법은 무엇입니까?

big-blog 2020. 2. 23. 11:55
반응형

Java에서 함수를 매개 변수로 전달하는 방법은 무엇입니까? [복제]


이 질문에는 이미 답변이 있습니다.

메소드를 Java 메소드에 매개 변수로 전달할 수 있습니까? 그렇다면 누군가 나를 안내해 주시겠습니까? 이것은 사소한 것 같지 않습니다


자바 8 이상

단일 추상 메소드 ( SAM type 이라고도 함) 만있는 클래스 또는 인터페이스가있는 경우 Java 8 이상 람다 식 사용 :

public interface MyInterface {
    String doSomething(int param1, String param2);
}

MyInterface가 사용되는 곳이라면 람다 식을 대신 사용할 수 있습니다.

class MyClass {
    public MyInterface myInterface = (p1, p2) -> { return p2 + p1; };
}

예를 들어, 새 스레드를 매우 빠르게 만들 수 있습니다.

new Thread(() -> someMethod()).start();

그리고 메소드 참조 구문 을 사용하여 더 깨끗하게 만듭니다.

new Thread(this::someMethod).start();

람다식이 없으면 이 마지막 두 예는 다음과 같습니다.

new Thread(new Runnable() { someMethod(); }).start();

Java 8 이전

일반적인 패턴은 인터페이스와 같은 인터페이스 내에서 '랩핑'하는 것 Callable입니다. 예를 들어 Callable을 전달합니다.

public T myMethod(Callable<T> func) {
    return func.call();
}

이 패턴을 명령 패턴이라고 합니다.

특정 용도에 맞는 인터페이스를 만드는 것이 가장 좋습니다. 호출 가능하게 선택하면 위와 같이 T를 문자열과 같이 기대하는 유형의 반환 값으로 대체하십시오.

아래에 귀하의 의견에 대한 답변으로 말할 수 있습니다 :

public int methodToPass() { 
        // do something
}

public void dansMethod(int i, Callable<Integer> myFunc) {
       // do something
}

그런 다음 익명의 내부 클래스를 사용하여 호출하십시오.

dansMethod(100, new Callable<Integer>() {
   public Integer call() {
        return methodToPass();
   }
});

이것은 '속임수'가 아님을 명심하십시오. 함수 포인터와 동등한 Java의 기본 개념입니다.


이를 위해 Java 리플렉션을 사용할 수 있습니다. 메소드는 java.lang.reflect.Method 의 인스턴스로 표시됩니다 .

import java.lang.reflect.Method;

public class Demo {

    public static void main(String[] args) throws Exception{
        Class[] parameterTypes = new Class[1];
        parameterTypes[0] = String.class;
        Method method1 = Demo.class.getMethod("method1", parameterTypes);

        Demo demo = new Demo();
        demo.method2(demo, method1, "Hello World");
    }

    public void method1(String message) {
        System.out.println(message);
    }

    public void method2(Object object, Method method, String message) throws Exception {
        Object[] parameters = new Object[1];
        parameters[0] = message;
        method.invoke(object, parameters);
    }

}

람다 식

jk.의 탁월한 답변 을 더하기 위해 이제 Lambda Expressions (Java 8)를 사용하여 더 쉽게 메소드를 전달할 수 있습니다 . 먼저, 일부 배경. 기능 인터페이스 는 임의의 수의 포함 할 수 있지만, 오직 하나의 추상 메소드가있는 인터페이스입니다 기본 방법 과 정적 메소드 (자바 8의 새로운 기능). 람다 식을 사용하지 않으면 필요한 모든 구문없이 람다 식을 사용하여 추상 메서드를 빠르게 구현할 수 있습니다.

람다식이 없으면 :

obj.aMethod(new AFunctionalInterface() {
    @Override
    public boolean anotherMethod(int i)
    {
        return i == 982
    }
});

람다 식의 경우 :

obj.aMethod(i -> i == 982);

다음은 Lambda Expressions에 대한 Java 자습서에서 발췌 한 내용입니다 .

람다 식의 구문

람다 식은 다음과 같이 구성됩니다.

  • 괄호로 묶인 쉼표로 구분 된 공식 매개 변수 목록입니다. CheckPerson.test 메소드에는 Person 클래스의 인스턴스를 나타내는 하나의 매개 변수 p가 있습니다.

    참고 : 람다 식에서 매개 변수의 데이터 형식을 생략 할 수 있습니다. 또한 매개 변수가 하나만 있으면 괄호를 생략 할 수 있습니다. 예를 들어 다음 람다 식도 유효합니다.

    p -> p.getGender() == Person.Sex.MALE 
        && p.getAge() >= 18
        && p.getAge() <= 25
    
  • 화살표 토큰 ->

  • 본문은 단일 표현식 또는 명령문 블록으로 구성됩니다. 이 예제는 다음 표현식을 사용합니다.

    p.getGender() == Person.Sex.MALE 
        && p.getAge() >= 18
        && p.getAge() <= 25
    

    단일 표현식을 지정하면 Java 런타임이 표현식을 평가 한 후 해당 값을 리턴합니다. 또는 return 문을 사용할 수 있습니다.

    p -> {
        return p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25;
    }
    

    리턴 문은 표현식이 아닙니다. 람다 식에서는 중괄호 ({})로 문을 묶어야합니다. 그러나 void 메소드 호출을 중괄호로 묶을 필요는 없습니다. 예를 들어 다음은 유효한 람다 식입니다.

    email -> System.out.println(email)
    

람다 식은 메서드 선언과 매우 비슷합니다. 람다 식을 이름없는 메서드 인 익명 메서드로 간주 할 수 있습니다.


람다 식을 사용하여 "메소드를 전달하는"방법은 다음과 같습니다.

참고 : 이것은 새로운 표준 기능 인터페이스 인를 사용합니다 java.util.function.IntConsumer.

class A {
    public static void methodToPass(int i) { 
        // do stuff
    }
}
import java.util.function.IntConsumer;

class B {
    public void dansMethod(int i, IntConsumer aMethod) {
        /* you can now call the passed method by saying aMethod.accept(i), and it
        will be the equivalent of saying A.methodToPass(i) */
    }
}
class C {
    B b = new B();

    public C() {
        b.dansMethod(100, j -> A.methodToPass(j));   //Lambda Expression here
    }
}

위의 예는 ::연산자를 사용하여 훨씬 더 단축 될 수 있습니다 .

public C() {
    b.dansMethod(100, A::methodToPass);
}

Java 8 덕분에 함수에 메소드를 전달하기 위해 아래 단계를 수행 할 필요가 없습니다. 즉, 람다는 무엇입니까, Oracle의 Lambda Expression tutorial을 참조하십시오 . 이 게시물의 나머지 부분에서는이 기능을 구현하기 위해 과거의 나쁜 시절에해야했던 작업에 대해 설명합니다.

일반적으로 단일 메소드를 사용하여 인터페이스를 취하는 것으로 메소드를 선언 한 다음 해당 인터페이스를 구현하는 오브젝트를 전달합니다. 클로저, 트랜스포머 및 술어에 대한 인터페이스와 해당 구현을 전달하는 메소드가있는 공통 콜렉션에 예가 있습니다. 구아바는 새로운 개선 된 공통 모음입니다.

예를 들어 commons-collections에는 org.apache.commons.collections.CollectionUtils가 있습니다.이 메소드에는 객체를 전달하고 무작위로 하나를 선택하는 많은 정적 메소드가 있으며이 서명이있는 메소드가 있습니다.

static boolean exists(java.util.Collection collection, Predicate predicate) 

Predicate 인터페이스를 구현하는 객체를 가져옵니다. 즉, 일부 Object를 가져 와서 부울을 반환하는 메서드가 있어야합니다.

그래서 나는 이것을 다음과 같이 부를 수 있습니다.

CollectionUtils.exists(someCollection, new Predicate() {
    public boolean evaluate(Object object) { 
        return ("a".equals(object.toString());
    }
});

someCollection술어가 true를 리턴하는 오브젝트를 포함 하는지에 따라 true 또는 false를 리턴합니다.

어쨌든 이것은 단지 예일 뿐이며 커먼즈 컬렉션은 구식입니다. 구아바에서 그와 동등한 것을 잊어 버렸습니다.


Java는 클로저를 잘 지원합니다. 함수 만 지원하지 않으므로 클로저에 사용되는 구문이 훨씬 어색하고 부피가 큽니다. 메서드로 클래스의 모든 것을 감싸 야합니다. 예를 들어

public Runnable foo(final int x) {
  return new Runnable() {
    public void run() {
      System.out.println(x);
    }
  };
}

일급 함수와 클로저를 지원하는 모든 언어와 마찬가지로 전달 run()메서드가 "닫힌" Runnable 객체를 반환합니다 x.


@jk 명령 패턴을 사용했습니다. 언급 된 반환 유형 추가 :

public interface Callable<I, O> {

    public O call(I input);   
}

나는 이것이 다소 오래된 게시물이라는 것을 알고 있지만 약간 더 간단한 해결책이 있습니다. 내부에 다른 클래스를 만들어 추상화 할 수 있습니다. 그런 다음 추상 메소드 이름을 원하는대로 만듭니다. 원래 클래스에서 새 클래스를 매개 변수로 사용하는 메소드를 작성하십시오.이 메소드에서 추상 메소드를 호출하십시오. 이런 식으로 보일 것입니다.

public class Demo {

    public Demo(/.../){

    }

    public void view(Action a){
        a.preform();
    }

    /**
     * The Action Class is for making the Demo
     * View Custom Code
     */
    public abstract class Action {

        public Action(/.../){

        }

        abstract void preform();
    }
}

이제 클래스 내에서 메소드를 호출하기 위해 이와 같은 작업을 수행 할 수 있습니다.

/...
Demo d = new Demo;
Action a = new Action() {

    @Override
    void preform() {
        //Custom Method Code Goes Here
    }
};

/.../
d.view(a)

내가 말했듯이 나는 그것의 오래된 것을 알고 있지만이 방법은 조금 더 쉽다고 생각합니다. 도움이 되길 바랍니다.


Java는 (아직) 클로저를 지원하지 않습니다. 그러나 Scala 및 Groovy와 같은 다른 언어 가 JVM에서 실행되며 클로저를 지원합니다.

참고 URL : https://stackoverflow.com/questions/4685563/how-to-pass-a-function-as-a-parameter-in-java



반응형