source

Java에서 함수를 매개 변수로 전달하려면 어떻게 해야 합니까?

goodcode 2022. 8. 1. 22:43
반응형

Java에서 함수를 매개 변수로 전달하려면 어떻게 해야 합니까?

자바에서는 어떤 함수를 다른 함수의 인수로 넘길 수 있나요?

Java 8 이상

Java 8+ lamda 식을 사용하는 경우 추상 메서드(SAM 유형이라고도 함)가 하나뿐인 클래스 또는 인터페이스가 있는 경우 다음과 같습니다.

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콜러블

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

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

특정 용도에 맞는 인터페이스를 작성하는 것이 가장 좋습니다.호출 가능을 선택한 경우 위의 T를 String과 같은 원하는 유형의 반환 값으로 대체합니다.

아래의 코멘트에 대한 답변은 다음과 같습니다.

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 인스턴스로 표시됩니다.방법.

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에서)를 사용하여 메서드를 보다 쉽게 전달할 수 있습니다.일단 배경부터 말씀드릴게요.기능 인터페이스는 추상적인 메서드가1개밖에 없는 인터페이스입니다만, 임의의 수의 디폴트 메서드(Java 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가 1개 포함되어 있습니다.

    참고: 람다 식에서 모수의 데이터 유형을 생략할 수 있습니다.또한 파라미터가1개밖에 없는 경우에는 괄호를 생략할 수 있습니다.예를 들어, 다음 람다 식도 유효합니다.

    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)
    

람다 표현식은 메서드 선언과 매우 유사합니다. 람다 표현식은 익명 메서드(이름 없는 메서드)로 간주할 수 있습니다.


다음은 람다 식을 사용하여 메서드를 "통과"하는 방법입니다.

주의: 새로운 표준 기능 인터페이스를 사용합니다.

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 튜토리얼을 참조하십시오.이 투고의 나머지 부분에서는, 이 기능을 실장하기 위해서, 불경기의 시대에 무엇을 할 필요가 있었는지 설명합니다.

일반적으로 하나의 메서드로 어떤 인터페이스를 사용한다고 선언한 후 해당 인터페이스를 구현하는 개체를 전달합니다.예를 들어 commons-collections에서는 Closure, Transformer 및 Predicate의 인터페이스와 이러한 구현을 전달하는 메서드가 있습니다.Guava는 새롭게 개선된 공통 컬렉션으로, 동등한 인터페이스를 찾을 수 있습니다.

예를 들어 commons-collections에는 org.apache.commons.collections가 있습니다.Collection Utils는 전달된 객체를 랜덤으로 선택하는 많은 정적 메서드를 가지고 있으며, 이 시그니처에 의해 호출된 객체가 존재합니다.

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

인터페이스 Predicate를 구현하는 객체를 취득합니다.즉, 객체를 취득하고 부울을 반환하는 메서드가 필요합니다.

그래서 이렇게 부를 수 있어요.

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

이 값은 true 또는 false로 반환됩니다.someCollection에는 술어가 true를 반환하는 객체가 포함되어 있습니다.

어쨌든, 이것은 단지 하나의 예에 불과하고, 공유 수집은 시대에 뒤떨어진 것이다.나는 단지 과바의 동등한 것을 잊었다.

자바는 폐쇄를 잘 지원한다.기능을 지원하지 않기 때문에 폐쇄에 익숙한 구문은 훨씬 더 어색하고 부피가 커집니다. 수업에서 모든 것을 메서드로 마무리해야 합니다.예를들면,

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

Runnable 개체를 반환합니다.run()method "오버"는x1등급 기능 및 폐쇄를 지원하는 다른 언어처럼 통과되었습니다.

명령어 pattern that@jk.mentioned를 사용하여 반환 유형을 추가했습니다.

public interface Callable<I, O> {

    public O call(I input);   
}

이것은 꽤 오래된 포스트라는 것을 알지만, 조금 더 간단한 해결책이 하나 더 있습니다.다른 클래스를 생성하여 추상화할 수 있습니다.다음으로 Abstract 메서드에 원하는 이름을 붙입니다.원래 클래스에서 새 클래스를 매개 변수로 사용하는 메서드를 만듭니다. 이 메서드에서는 추상 메서드를 호출합니다.이렇게 생겼을 거예요.

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는 아직 폐쇄를 지원하지 않습니다.그러나 JVM에서 실행되어 폐쇄를 지원하는 Scala 및 Groovy와 같은 다른 언어도 있습니다.

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

반응형