programing

파라미터로서의 Java Pass 메서드

prostudy 2022. 7. 23. 09:16
반응형

파라미터로서의 Java Pass 메서드

나는 어떤 방법을 참고해서 통과시킬 방법을 찾고 있다.자바가 메서드를 파라미터로 전달하지 않는 것은 알고 있습니다만, 대체 방법을 찾고 싶습니다.

파라미터로서 메서드를 전달하는 대신 인터페이스가 있다고 들었습니다만, 인터페이스가 어떻게 참조에 의해 메서드로 기능할 수 있는지 이해할 수 없습니다.올바르게 이해했다면 인터페이스는 정의되지 않은 추상적인 메서드 세트일 뿐입니다.여러 개의 다른 메서드가 동일한 파라미터로 동일한 메서드를 호출할 수 있기 때문에 매번 정의할 필요가 있는 인터페이스를 송신하고 싶지 않습니다.

제가 이루고 싶은 것은 다음과 같습니다.

public void setAllComponents(Component[] myComponentArray, Method myMethod) {
    for (Component leaf : myComponentArray) {
        if (leaf instanceof Container) { //recursive call if Container
            Container node = (Container) leaf;
            setAllComponents(node.getComponents(), myMethod);
        } //end if node
        myMethod(leaf);
    } //end looping through components
}

다음과 같이 호출됩니다.

setAllComponents(this.getComponents(), changeColor());
setAllComponents(this.getComponents(), changeSize());

편집: Java 8에서 람다 표현식은 다른 답변에서 지적한 바와 같이 훌륭한 솔루션입니다.아래 답변은 Java 7 이전 버전으로 작성되었습니다.


명령어 패턴을 확인합니다.

// NOTE: code not tested, but I believe this is valid java...
public class CommandExample 
{
    public interface Command 
    {
        public void execute(Object data);
    }

    public class PrintCommand implements Command 
    {
        public void execute(Object data) 
        {
            System.out.println(data.toString());
        }    
    }

    public static void callCommand(Command command, Object data) 
    {
        command.execute(data);
    }

    public static void main(String... args) 
    {
        callCommand(new PrintCommand(), "hello world");
    }
}

편집: Pete Kirkham이 지적한 바와 같이 Visitor를 사용하는 다른 방법이 있습니다.방문자 접근 방식은 좀 더 복잡합니다. 노드가 모두 방문자를 인식해야 합니다.acceptVisitor()방법 - 그러나 더 복잡한 객체 그래프를 이동해야 하는 경우에는 검토할 필요가 있습니다.

Java 8에서는 이제 람다 식과 메서드 참조를 사용하여 메서드를 더 쉽게 전달할 수 있습니다.첫 번째 배경: 기능 인터페이스는 하나의 추상적인 메서드를 가진 인터페이스입니다.다만, 임의의 수의 디폴트 메서드(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)
    

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


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

interface I {
    public void myMethod(Component component);
}

class A {
    public void changeColor(Component component) {
        // code here
    }

    public void changeSize(Component component) {
        // code here
    }
}
class B {
    public void setAllComponents(Component[] myComponentArray, I myMethodsInterface) {
        for(Component leaf : myComponentArray) {
            if(leaf instanceof Container) { // recursive call if Container
                Container node = (Container)leaf;
                setAllComponents(node.getComponents(), myMethodInterface);
            } // end if node
            myMethodsInterface.myMethod(leaf);
        } // end looping through components
    }
}
class C {
    A a = new A();
    B b = new B();

    public C() {
        b.setAllComponents(this.getComponents(), component -> a.changeColor(component));
        b.setAllComponents(this.getComponents(), component -> a.changeSize(component));
    }
}

★★C는, 보다, 보다, 보다, 보다, 보다, 보다, 보다, 라고 하는 메서드 더 할 수 .

class C {
    A a = new A();
    B b = new B();

    public C() {
        b.setAllComponents(this.getComponents(), a::changeColor);
        b.setAllComponents(this.getComponents(), a::changeSize);
    }
}

이 있기 때문에 8이 .Function<T, R>interface(interface) - 메서드가 있습니다.

R apply(T t);

이 명령을 사용하여 기능을 다른 함수에 파라미터로 전달할 수 있습니다.T는 함수의 입력 유형이고 R은 반환 유형입니다.

에서는 '수능하다'를 사용하는 .Component하지 않습니다.Void ★★★★Function<T, R>Void 타입의 자동 박스는 없기 때문에, 최선은 아닙니다. 있는 는 """ 입니다.Consumer<T>(7) 방법에 따라

void accept(T t);

다음과 같습니다.

public void setAllComponents(Component[] myComponentArray, Consumer<Component> myMethod) {
    for (Component leaf : myComponentArray) {
        if (leaf instanceof Container) { 
            Container node = (Container) leaf;
            setAllComponents(node.getComponents(), myMethod);
        } 
        myMethod.accept(leaf);
    } 
}

메서드 참조를 사용하여 다음과 같이 부를 수 있습니다.

setAllComponents(this.getComponents(), this::changeColor);
setAllComponents(this.getComponents(), this::changeSize); 

같은 클래스에 changeColor() 메서드와 changeSize() 메서드가 정의되어 있다고 가정합니다.


중인 메서드에서 매개 변수를 할 수 .BiFunction<T, U, R>, 유형입니다 T u U 、 R 은 - 。, there있있 there 도 있다.BiConsumer<T, U>(2개).유감스럽게도 3개 이상의 입력 파라미터의 경우 사용자가 직접 인터페이스를 작성해야 합니다.예를 들어 다음과 같습니다.

public interface Function4<A, B, C, D, R> {

    R apply(A a, B b, C c, D d);
}

하다를 사용하세요.java.lang.reflect.Method 및 콜 " " "invoke

먼저 매개 변수로 전달할 메서드를 사용하여 인터페이스를 정의합니다.

public interface Callable {
  public void call(int param);
}

메서드를 사용하여 클래스 구현

class Test implements Callable {
  public void call(int param) {
    System.out.println( param );
  }
}

// 이렇게 호출합니다.

Callable cmd = new Test();

이를 통해 cmd를 파라미터로 전달하고 인터페이스에 정의된 메서드 호출을 호출할 수 있습니다.

public invoke( Callable callable ) {
  callable.call( 5 );
}

Java 7 이하에서는 아직 유효하지 않지만, Java 8 등 새로운 버전에서의 변경에 대해서는 미래를 내다보고 인식해야 한다고 생각합니다.

즉, 이 새로운 버전은 (이 문제에 대한 또 다른 유효한 해결책인) 새로운 API와 함께 람다 및 메서드 참조를 Java로 가져옵니다.인터페이스가 필요한 경우에도 새로운 오브젝트는 생성되지 않으며 추가 클래스 파일이 JVM에 의한 다른 처리로 인해 출력 디렉토리를 오염시킬 필요는 없습니다.

두 플레이버(lambda 및 메서드레퍼런스) 모두 시그니처가 사용되는 단일 메서드로 사용 가능한 인터페이스가 필요합니다.

public interface NewVersionTest{
    String returnAString(Object oIn, String str);
}

이제부터는 메서드의 이름은 중요하지 않습니다.람다가 받아들여지는 경우 방법 참조도 마찬가지입니다.예를 들어, 여기에 서명을 사용하는 경우:

public static void printOutput(NewVersionTest t, Object o, String s){
    System.out.println(t.returnAString(o, s));
}

이것은1 람다가 통과할 때까지의 단순한 인터페이스 호출입니다.

public static void main(String[] args){
    printOutput( (Object oIn, String sIn) -> {
        System.out.println("Lambda reached!");
        return "lambda return";
    }
    );
}

다음과 같이 출력됩니다.

Lambda reached!
lambda return

메서드 참조는 유사합니다.지정:

public class HelperClass{
    public static String testOtherSig(Object o, String s){
        return "real static method";
    }
}

및 메인:

public static void main(String[] args){
    printOutput(HelperClass::testOtherSig);
}

출력은 다음과 같습니다.real static method. 메서드 참조는 static, instance, 임의의 instance를 사용하는 non-static, 심지어 컨스트럭터일 수도 있습니다.건설업자에게 다음과 같은 것이 있습니다.ClassName::new용됩니니다다

1 이것은 부작용이 있기 때문에 일부에서는 람다라고 생각하지 않는다.그러나, 이것은 보다 시각적으로 알기 쉬운 방법으로 하나를 사용하는 것을 시각화할 수 있습니다.

마지막으로 확인했을 때 Java는 기본적으로 원하는 작업을 수행할 수 없습니다. 이러한 제한을 피하기 위해 '회피책'을 사용해야 합니다.제가 보기엔 인터페이스가 대안이지만 좋은 대안이라고 할 수는 없습니다.아마 누가 그런 말을 했든 간에 이런 뜻이겠죠

public interface ComponentMethod {
  public abstract void PerfromMethod(Container c);
}

public class ChangeColor implements ComponentMethod {
  @Override
  public void PerfromMethod(Container c) {
    // do color change stuff
  }
}

public class ChangeSize implements ComponentMethod {
  @Override
  public void PerfromMethod(Container c) {
    // do color change stuff
  }
}

public void setAllComponents(Component[] myComponentArray, ComponentMethod myMethod) {
    for (Component leaf : myComponentArray) {
        if (leaf instanceof Container) { //recursive call if Container
            Container node = (Container) leaf;
            setAllComponents(node.getComponents(), myMethod);
        } //end if node
        myMethod.PerfromMethod(leaf);
    } //end looping through components
}

그런 다음 호출할 수동을 걸 수 있습니다.

setAllComponents(this.getComponents(), new ChangeColor());
setAllComponents(this.getComponents(), new ChangeSize());

이러한 메서드가 필요하지 않은 경우 Runnable 개체를 반환할 수 있습니다.

private Runnable methodName (final int arg) {
    return (new Runnable() {
        public void run() {
          // do stuff with arg
        }
    });
}

다음으로 다음과 같이 사용합니다.

private void otherMethodName (Runnable arg){
    arg.run();
}

수 .java.util.function.Function파라미터 함수로 간단한 방법을 사용합니다.하다

import java.util.function.Function;

public class Foo {

  private Foo(String parameter) {
    System.out.println("I'm a Foo " + parameter);
  }

  public static Foo method(final String parameter) {
    return new Foo(parameter);
  }

  private static Function parametrisedMethod(Function<String, Foo> function) {
    return function;
  }

  public static void main(String[] args) {
    parametrisedMethod(Foo::method).apply("from a method");
  }
}

으로는 ★★★★★★★★★★★★★★★★★★★★★.Foo기본 생성자가 있는 개체입니다. a.method from터 the the that that that that that that that that that that that that that that that that 。parametrisedMethodFunction<String, Foo>.

  • Function<String, Foo>가 「」, 「」를 합니다.String 변수로 됩니다.Foo.
  • Foo::Methodx -> Foo.method(x);
  • parametrisedMethod(Foo::method)라고 볼 수 x -> parametrisedMethod(Foo.method(x))
  • .apply("from a method")으로 하는 것이다parametrisedMethod(Foo.method("from a method"))

그러면 출력이 반환됩니다.

>> I'm a Foo from a method

이 예는 그대로 실행되어야 합니다.그러면 다른 클래스 및 인터페이스를 사용하여 위의 답변에서 좀 더 복잡한 것을 시도할 수 있습니다.

Java-8 이후

Java 8 이후로는 람다 식을 사용하여 기능 인터페이스(추상 메서드가1개뿐인 인터페이스)의 추상 메서드를 구현하고 이를 파라미터로 메서드에 전달할 수 있습니다.

@FunctionalInterface
interface ArithmeticFunction {
    public int calcualate(int a, int b);
}

public class Main {
    public static void main(String args[]) {
        ArithmeticFunction addition = (a, b) -> a + b;
        ArithmeticFunction subtraction = (a, b) -> a - b;

        int a = 20, b = 5;

        System.out.println(perform(addition, a, b));
        // or
        System.out.println(perform((x, y) -> x + y, a, b));

        System.out.println(perform(subtraction, a, b));
        // or
        System.out.println(perform((x, y) -> x - y, a, b));
    }

    static int perform(ArithmeticFunction function, int a, int b) {
        return function.calcualate(a, b);
    }
}

출력:

25
25
15
15

ONLINE DEMO

자세한 내용은 Method Reference를 참조하십시오.

Java에는 이름을 전달하고 호출하는 메커니즘이 있습니다.이것은 반사 메커니즘의 일부입니다.함수는 Method 클래스의 추가 파라미터를 취해야 합니다.

public void YouMethod(..... Method methodToCall, Object objWithAllMethodsToBeCalled)
{
...
Object retobj = methodToCall.invoke(objWithAllMethodsToBeCalled, arglist);
...
}

메서드의 파라미터로 바인드된 메서드를 통과하는 방법을 보여 주는 솔루션을 찾을 수 없었습니다.Bellow는 매개 변수 값이 이미 결합되어 있는 메서드를 전달하는 방법의 예입니다.

  1. 스텝 1: 2개의 인터페이스를 만듭니다.하나는 리턴 타입의 인터페이스, 다른 하나는 리턴 타입의 인터페이스를 만듭니다.Java는 비슷한 인터페이스를 가지고 있지만 예외 송출을 지원하지 않기 때문에 실용성은 거의 없습니다.


    public interface Do {
    void run() throws Exception;
    }


    public interface Return {
        R run() throws Exception;
    }

  1. 트랜잭션에서 메서드콜을 랩하기 위해 양쪽 인터페이스를 사용하는 방법의 예.실제 매개 변수를 사용하여 메서드를 전달합니다.


    //example - when passed method does not return any value
    public void tx(final Do func) throws Exception {
        connectionScope.beginTransaction();
        try {
            func.run();
            connectionScope.commit();
        } catch (Exception e) {
            connectionScope.rollback();
            throw e;
        } finally {
            connectionScope.close();
        }
    }

    //Invoke code above by 
    tx(() -> api.delete(6));

또 다른 예는 실제로 무언가를 반환하는 메서드를 통과하는 방법을 보여줍니다.



        public  R tx(final Return func) throws Exception {
    R r=null;
    connectionScope.beginTransaction();
    try {
                r=func.run();
                connectionScope.commit();
            } catch (Exception e) {
                connectionScope.rollback();
                throw e;
            } finally {
                connectionScope.close();
            }
        return r;
        }
        //Invoke code above by 
        Object x= tx(() -> api.get(id));

옵저버 패턴(청취자 패턴이라고도 함)을 사용합니다.

interface ComponentDelegate {
    void doSomething(Component component);
}

public void setAllComponents(Component[] myComponentArray, ComponentDelegate delegate) {
    // ...
    delegate.doSomething(leaf);
}

setAllComponents(this.getComponents(), new ComponentDelegate() {
                                            void doSomething(Component component) {
                                                changeColor(component); // or do directly what you want
                                            }
                                       });

new ComponentDelegate()...는, 인터페이스를 실장하고 있는 어나니머스 타입을 선언합니다.

기본적인 예를 다음에 나타냅니다.

public class TestMethodPassing
{
    private static void println()
    {
        System.out.println("Do println");
    }

    private static void print()
    {
        System.out.print("Do print");
    }

    private static void performTask(BasicFunctionalInterface functionalInterface)
    {
        functionalInterface.performTask();
    }

    @FunctionalInterface
    interface BasicFunctionalInterface
    {
        void performTask();
    }

    public static void main(String[] arguments)
    {
        performTask(TestMethodPassing::println);
        performTask(TestMethodPassing::print);
    }
}

출력:

Do println
Do print

자바 전문가는 아니지만 다음과 같이 문제를 해결합니다.

@FunctionalInterface
public interface AutoCompleteCallable<T> {
  String call(T model) throws Exception;
}

특수 인터페이스에서 매개 변수를 정의합니다.

public <T> void initialize(List<T> entries, AutoCompleteCallable getSearchText) {.......
//call here
String value = getSearchText.call(item);
...
}

마지막으로 초기화 메서드를 호출하면서 getSearchText 메서드를 구현합니다.

initialize(getMessageContactModelList(), new AutoCompleteCallable() {
          @Override
          public String call(Object model) throws Exception {
            return "custom string" + ((xxxModel)model.getTitle());
          }
        })

반사가 포함된 솔루션의 예, 전달된 메서드는 공용이어야 합니다.

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

public class Program {
    int i;

    public static void main(String[] args) {
        Program   obj = new Program();    //some object

        try {
            Method method = obj.getClass().getMethod("target");
            repeatMethod( 5, obj, method );
        } 
        catch ( NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            System.out.println( e ); 
        }
    }

    static void repeatMethod (int times, Object object, Method method)
        throws IllegalAccessException, InvocationTargetException {

        for (int i=0; i<times; i++)
            method.invoke(object);
    }
    public void target() {                 //public is necessary
        System.out.println("target(): "+ ++i);
    }
}

위의 답변은 감사하지만, Javascript 콜백에서 아이디어를 차용한 아래의 방법으로 같은 동작을 할 수 있었습니다.아직까지는 괜찮지만 정정할 의향이 있습니다.

시그니처에 함수의 반환 타입을 사용하는 것이 목적입니다.즉, 수율은 정적인 것이어야 합니다.

다음은 타임아웃이 설정된 프로세스를 실행하는 함수입니다.

public static void timeoutFunction(String fnReturnVal) {

    Object p = null; // whatever object you need here

    String threadSleeptime = null;

    Config config;

    try {
        config = ConfigReader.getConfigProperties();
        threadSleeptime = config.getThreadSleepTime();

    } catch (Exception e) {
        log.error(e);
        log.error("");
        log.error("Defaulting thread sleep time to 105000 miliseconds.");
        log.error("");
        threadSleeptime = "100000";
    }

    ExecutorService executor = Executors.newCachedThreadPool();
    Callable<Object> task = new Callable<Object>() {
        public Object call() {
            // Do job here using --- fnReturnVal --- and return appropriate value
            return null;
        }
    };
    Future<Object> future = executor.submit(task);

    try {
        p = future.get(Integer.parseInt(threadSleeptime), TimeUnit.MILLISECONDS);
    } catch (Exception e) {
        log.error(e + ". The function timed out after [" + threadSleeptime
                + "] miliseconds before a response was received.");
    } finally {
        // if task has started then don't stop it
        future.cancel(false);
    }
}

private static String returnString() {
    return "hello";
}

public static void main(String[] args) {
    timeoutFunction(returnString());
}

언급URL : https://stackoverflow.com/questions/2186931/java-pass-method-as-parameter

반응형