programing

: :( 이중 콜론) 연산자 (Java 8)

nasanasas 2020. 9. 28. 09:15
반응형

: :( 이중 콜론) 연산자 (Java 8)


저는 Java 8 소스를 탐색하고 있었고 코드의이 특정 부분이 매우 놀랍다는 것을 알았습니다.

//defined in IntPipeline.java
@Override
public final OptionalInt reduce(IntBinaryOperator op) {
    return evaluate(ReduceOps.makeInt(op));
}

@Override
public final OptionalInt max() {
    return reduce(Math::max); //this is the gotcha line
}

//defined in Math.java
public static int max(int a, int b) {
    return (a >= b) ? a : b;
}

인가 Math::max하는 방법 포인터처럼 뭔가? 일반적인 static방법은 어떻게 변환 IntBinaryOperator됩니까?


일반적 으로 다음과 같이 reduce메서드를 호출합니다 Math.max(int, int).

reduce(new IntBinaryOperator() {
    int applyAsInt(int left, int right) {
        return Math.max(left, right);
    }
});

그것은 단지 호출을 위해 많은 구문이 필요합니다 Math.max. 그것이 람다 표현이 작동하는 곳입니다. Java 8부터 훨씬 더 짧은 방법으로 동일한 작업을 수행 할 수 있습니다.

reduce((int left, int right) -> Math.max(left, right));

어떻게 작동합니까? Java 컴파일러는 두 개의를 받아들이고 int하나를 반환 하는 메서드를 구현하려는 것을 "감지" 합니다 int. 이것은 유일한 인터페이스 메소드 IntBinaryOperator( reduce호출하려는 메소드의 매개 변수)의 형식 매개 변수와 동일합니다 . 따라서 컴파일러가 나머지 작업을 수행 IntBinaryOperator합니다. 단지 구현을 원한다고 가정합니다 .

그러나 Math.max(int, int)자체적으로의 공식적인 요구 사항을 충족하므로 IntBinaryOperator직접 사용할 수 있습니다. Java 7에는 메서드 자체를 인수로 전달할 수있는 구문이 없기 때문에 (메소드 결과 만 전달할 수 있지만 메서드 참조는 전달할 수 없음)이 ::구문은 메서드를 참조하기 위해 Java 8에서 도입되었습니다.

reduce(Math::max);

이것은 런타임에 JVM이 아닌 컴파일러에 의해 해석됩니다! 세 코드 스 니펫 모두에 대해 다른 바이트 코드를 생성하지만 의미 상 동일하므로 마지막 두 개는 IntBinaryOperator구현 의 짧은 (그리고 아마도 더 효율적인) 버전으로 간주 될 수 있습니다 !

(또한 Lambda 표현식 번역 참조 )


::Method Reference라고합니다. 기본적으로 단일 메서드에 대한 참조입니다. 즉, 기존 방법을 이름으로 참조합니다.

간략한 설명 :
다음은 정적 메서드에 대한 참조의 예입니다.

class Hey {
     public static double square(double num){
        return Math.pow(num, 2);
    }
}

Function<Double, Double> square = Hey::square;
double ans = square.apply(23d);

square객체 참조처럼 전달되고 필요할 때 트리거 될 수 있습니다. 사실, 그것은 객체의 "정상적인"메소드에 대한 참조처럼 쉽게 사용될 수 있습니다 static. 예를 들면 :

class Hey {
    public double square(double num) {
        return Math.pow(num, 2);
    }
}

Hey hey = new Hey();
Function<Double, Double> square = hey::square;
double ans = square.apply(23d);

Function위는 기능적 인터페이스 입니다. 을 완전히 이해하려면 ::기능적 인터페이스도 이해하는 것이 중요합니다. 분명히 기능적 인터페이스 는 하나의 추상 메소드 만있는 인터페이스입니다.

기능 인터페이스의 예로 RunnableCallable, 및 ActionListener.

Function위는 하나의 방법으로 기능적 인터페이스입니다 : apply. 하나의 인수를 취하고 결과를 생성합니다.


::s가 멋진 이유 는 다음 같습니다.

메서드 참조는 람다 식 (...)과 동일하게 처리되는 식이지만 메서드 본문을 제공하는 대신 기존 메서드를 이름으로 참조합니다.

예를 들어 람다 본문을 작성하는 대신

Function<Double, Double> square = (Double x) -> x * x;

당신은 단순히 할 수 있습니다

Function<Double, Double> square = Hey::square;

런타임에이 두 square메서드는 서로 정확히 동일하게 작동합니다. 바이트 코드는 같을 수도 있고 같지 않을 수도 있습니다 (위의 경우 동일한 바이트 코드가 생성됩니다. 위를 컴파일하고으로 확인하십시오 javap -c).

충족 해야 할 유일한 주요 기준은 다음 같습니다. 제공하는 메소드는 객체 참조로 사용하는 기능 인터페이스의 메소드와 유사한 서명을 가져야합니다 .

아래는 불법입니다.

Supplier<Boolean> p = Hey::square; // illegal

square인수를 예상하고 double. Supplierget메서드 는 값을 반환하지만 인수를 사용하지 않습니다. 따라서 이로 인해 오류가 발생합니다.

메소드 참조는 기능 인터페이스의 메소드를 나타냅니다. (언급했듯이 기능 인터페이스는 각각 하나의 메서드 만 가질 수 있습니다.)

더 많은 예 : Consumeraccept메서드 는 입력을 받지만 아무것도 반환하지 않습니다.

Consumer<Integer> b1 = System::exit;   // void exit(int status)
Consumer<String[]> b2 = Arrays::sort;  // void sort(Object[] a)
Consumer<String> b3 = MyProgram::main; // void main(String... args)

class Hey {
    public double getRandom() {
        return Math.random();
    }
}

Callable<Double> call = hey::getRandom;
Supplier<Double> call2 = hey::getRandom;
DoubleSupplier sup = hey::getRandom;
// Supplier is functional interface that takes no argument and gives a result

getRandom는 인수를 취하지 않고 double. 따라서 인수 없음 및 반환double 기준을 충족하는 모든 기능 인터페이스를 사용할 수 있습니다.

다른 예시:

Set<String> set = new HashSet<>();
set.addAll(Arrays.asList("leo","bale","hanks"));
Predicate<String> pred = set::contains;
boolean exists = pred.test("leo");

매개 변수화 된 유형의 경우 :

class Param<T> {
    T elem;
    public T get() {
        return elem;
    }

    public void set(T elem) {
        this.elem = elem;
    }

    public static <E> E returnSame(E elem) {
        return elem;
    }
}

Supplier<Param<Integer>> obj = Param<Integer>::new;
Param<Integer> param = obj.get();
Consumer<Integer> c = param::set;
Supplier<Integer> s = param::get;

Function<String, String> func = Param::<String>returnSame;

메서드 참조는 다른 스타일을 가질 수 있지만 기본적으로 모두 동일한 의미를 가지며 간단히 람다로 시각화 할 수 있습니다.

  1. 정적 메서드 ( ClassName::methName)
  2. 특정 개체 ( instanceRef::methName) 의 인스턴스 메서드
  3. 특정 개체의 슈퍼 메서드 ( super::methName)
  4. 특정 유형 ( ClassName::methName) 의 임의 개체의 인스턴스 메서드
  5. 클래스 생성자 참조 ( ClassName::new)
  6. 배열 생성자 참조 ( TypeName[]::new)

추가 참조는 http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html을 참조 하십시오 .


응 그것은 사실이야. ::연산자 방법 - 참조에 사용된다. 따라서 클래스에서 정적 메서드를 사용하거나 객체에서 메서드를 추출 할 수 있습니다 . 생성자에도 동일한 연산자를 사용할 수 있습니다. 여기에 언급 된 모든 경우는 아래 코드 샘플에 예시되어 있습니다.

Oracle의 공식 문서는 여기 에서 찾을 수 있습니다 .

기사 에서 JDK 8 변경 사항에 대한 더 나은 개요를 얻을 수 있습니다 . 에서 의 메소드 / 생성자 참조 섹션 코드 예가 또한 제공된다 :

interface ConstructorReference {
    T constructor();
}

interface  MethodReference {
   void anotherMethod(String input);
}

public class ConstructorClass {
    String value;

   public ConstructorClass() {
       value = "default";
   }

   public static void method(String input) {
      System.out.println(input);
   }

   public void nextMethod(String input) {
       // operations
   }

   public static void main(String... args) {
       // constructor reference
       ConstructorReference reference = ConstructorClass::new;
       ConstructorClass cc = reference.constructor();

       // static method reference
       MethodReference mr = cc::method;

       // object method reference
       MethodReference mr2 = cc::nextMethod;

       System.out.println(cc.value);
   }
}

::기존 클래스의 메서드를 참조하는 데 사용되는 Java 8에 포함 된 새로운 연산자입니다. 클래스의 정적 메서드 및 비 정적 메서드를 참조 할 수 있습니다.

정적 메서드를 참조하는 경우 구문은 다음과 같습니다.

ClassName :: methodName 

비 정적 메서드를 참조하는 경우 구문은 다음과 같습니다.

objRef :: methodName

ClassName :: methodName

메서드를 참조하기위한 유일한 전제 조건은 메서드가 함수 인터페이스에 존재한다는 것입니다.이 인터페이스는 메서드 참조와 호환되어야합니다.

메서드 참조는 평가 될 때 기능 인터페이스의 인스턴스를 만듭니다.

검색 위치 : http://www.speakingcs.com/2014/08/method-references-in-java-8.html


조금 늦은 것 같지만 여기 내 2 센트가 있습니다. 람다 표현식은 익명 메소드를 만드는 데 사용됩니다. 기존 메서드를 호출하는 것 외에는 수행하지 않지만 이름으로 직접 메서드를 참조하는 것이 더 명확합니다. 그리고 방법 참조는 그 사용 방법 참조 연산자를 수행하는 우리 수 있습니다 ::.

각 직원이 이름과 등급을 가지고있는 다음과 같은 간단한 클래스를 고려하십시오.

public class Employee {
    private String name;
    private String grade;

    public Employee(String name, String grade) {
        this.name = name;
        this.grade = grade;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGrade() {
        return grade;
    }

    public void setGrade(String grade) {
        this.grade = grade;
    }
}

어떤 방법으로 반환 된 직원 목록이 있고 직원을 등급별로 정렬한다고 가정합니다. 익명 클래스 를 다음과 같이 사용할 수 있다는 것을 알고 있습니다 .

    List<Employee> employeeList = getDummyEmployees();

    // Using anonymous class
    employeeList.sort(new Comparator<Employee>() {
           @Override
           public int compare(Employee e1, Employee e2) {
               return e1.getGrade().compareTo(e2.getGrade());
           }
    });

여기서 getDummyEmployee ()는 다음과 같은 일부 메소드입니다.

private static List<Employee> getDummyEmployees() {
        return Arrays.asList(new Employee("Carrie", "C"),
                new Employee("Fanishwar", "F"),
                new Employee("Brian", "B"),
                new Employee("Donald", "D"),
                new Employee("Adam", "A"),
                new Employee("Evan", "E")
                );
    }

이제 Comparator 가 기능적 인터페이스 라는 것을 알았습니다 . 기능 인터페이스 (이 하나 이상의 기본 또는 정적 방법을 포함 할 수 있지만) 정확하게 하나의 추상 메소드를 사용하여 하나입니다. Lambda 표현식은의 구현을 제공 @FunctionalInterface하므로 기능적 인터페이스는 하나의 추상 메서드 만 가질 수 있습니다. 람다 식을 다음과 같이 사용할 수 있습니다.

employeeList.sort((e1,e2) -> e1.getGrade().compareTo(e2.getGrade())); // lambda exp

모든 것이 좋지만 클래스가 Employee비슷한 방법을 제공 한다면 어떻게 될까요?

public class Employee {
    private String name;
    private String grade;
    // getter and setter
    public static int compareByGrade(Employee e1, Employee e2) {
        return e1.grade.compareTo(e2.grade);
    }
}

이 경우 메서드 이름 자체를 사용하는 것이 더 명확 해집니다. 따라서 다음과 같이 메서드 참조를 사용하여 메서드를 직접 참조 할 수 있습니다.

employeeList.sort(Employee::compareByGrade); // method reference

문서에 따라 네 가지 종류의 메서드 참조가 있습니다.

+----+-------------------------------------------------------+--------------------------------------+
|    | Kind                                                  | Example                              |
+----+-------------------------------------------------------+--------------------------------------+
| 1  | Reference to a static method                          | ContainingClass::staticMethodName    |
+----+-------------------------------------------------------+--------------------------------------+
| 2  |Reference to an instance method of a particular object | containingObject::instanceMethodName | 
+----+-------------------------------------------------------+--------------------------------------+
| 3  | Reference to an instance method of an arbitrary object| ContainingType::methodName           |
|    | of a particular type                                  |                                      |  
+----+-------------------------------------------------------+--------------------------------------+
| 4  |Reference to a constructor                             | ClassName::new                       |
+------------------------------------------------------------+--------------------------------------+

이것은 Java 8의 메소드 참조입니다. oracle 문서는 여기에 있습니다 .

문서에 명시된대로 ...

메서드 참조 Person :: compareByAge는 정적 메서드에 대한 참조입니다.

다음은 특정 개체의 인스턴스 메서드에 대한 참조의 예입니다.

class ComparisonProvider {
    public int compareByName(Person a, Person b) {
        return a.getName().compareTo(b.getName());
    }

    public int compareByAge(Person a, Person b) {
        return a.getBirthday().compareTo(b.getBirthday());
    }
}

ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName); 

메서드 참조 myComparisonProvider :: compareByName은 myComparisonProvider 개체의 일부인 compareByName 메서드를 호출합니다. JRE는 메소드 유형 인수를 유추합니다.이 경우에는 (Person, Person)입니다.


:: 연산자 는 메소드 참조를 위해 Java 8에서 도입되었습니다. 메서드 참조는 하나의 메서드 만 실행하는 람다 식의 축약 구문입니다. 다음은 메서드 참조의 일반적인 구문입니다.

Object :: methodName

익명 클래스를 사용하는 대신 람다 식을 사용할 수 있다는 것을 알고 있습니다 . 그러나 때때로 람다 식은 실제로 다음과 같은 일부 메서드에 대한 호출 일뿐입니다.

Consumer<String> c = s -> System.out.println(s);

코드를 더 명확하게하기 위해 해당 람다 식을 메서드 참조로 변환 할 수 있습니다.

Consumer<String> c = System.out::println;

::는 메서드 참조로 알려져 있습니다. Purchase 클래스의 calculatePrice 메서드를 호출한다고 가정 해 보겠습니다. 그런 다음 다음과 같이 작성할 수 있습니다.

Purchase::calculatePrice

메서드 참조가 람다 식으로 변환되기 때문에 람다 식을 작성하는 짧은 형식으로 볼 수도 있습니다.


런타임시 정확히 동일하게 동작합니다. 바이트 코드는 동일 할 수도 있고 동일하지 않을 수도 있습니다 (위 Incase의 경우 동일한 바이트 코드를 생성합니다 (위의 내용을 준수하고 javaap -c; 확인)).

런타임에 그들은 정확히 동일하게 작동합니다 .method (math :: max) ;, 동일한 수학을 생성합니다 (위를 따르고 javap -c;를 확인하십시오))


return reduce(Math::max);이다 NOT EQUAL은return reduce(max());

그러나 이것은 다음과 같은 것을 의미합니다.

IntBinaryOperator myLambda = (a, b)->{(a >= b) ? a : b};//56 keystrokes I had to type -_-
return reduce(myLambda);

이렇게 작성 하면 47 개의 키 입력을 저장할 수 있습니다.

return reduce(Math::max);//Only 9 keystrokes ^_^

여기에 많은 답변이 잘 설명되었으므로 ::추가로 :: 연산자가 인스턴스 변수에 사용되는 경우 참조하는 기능 인터페이스와 정확히 동일한 서명을 가질 필요가 없음 을 명확히하고 싶습니다 . TestObject 유형을 가진 BinaryOperator 가 필요하다고 가정 해 봅시다 . 전통적인 방식으로 다음과 같이 구현됩니다.

BinaryOperator<TestObject> binary = new BinaryOperator<TestObject>() {

        @Override
        public TestObject apply(TestObject t, TestObject u) {

            return t;
        }
    };

익명 구현에서 볼 수 있듯이 두 개의 TestObject 인수가 필요하며 TestObject 개체도 반환합니다. ::연산자 를 사용하여이 조건을 충족하기 위해 정적 메서드로 시작할 수 있습니다.

public class TestObject {


    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

그리고 전화 :

BinaryOperator<TestObject> binary = TestObject::testStatic;

좋아, 잘 컴파일되었습니다. 인스턴스 메서드가 필요하면 어떨까요? 인스턴스 메서드로 TestObject를 업데이트 할 수 있습니다.

public class TestObject {

    public final TestObject testInstance(TestObject t, TestObject t2){
        return t;
    }

    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

이제 아래와 같이 인스턴스에 액세스 할 수 있습니다.

TestObject testObject = new TestObject();
BinaryOperator<TestObject> binary = testObject::testInstance;

이 코드는 잘 컴파일되지만 하나 이하에서는 컴파일되지 않습니다.

BinaryOperator<TestObject> binary = TestObject::testInstance;

내 이클립스는 "TestObject 유형에서 비 정적 메서드 testInstance (TestObject, TestObject)에 대한 정적 참조를 만들 수 없습니다."라고 말합니다.

인스턴스 메서드는 충분하지만 testInstance아래와 같이 오버로드 하면 :

public class TestObject {

    public final TestObject testInstance(TestObject t){
        return t;
    }

    public final TestObject testInstance(TestObject t, TestObject t2){
        return t;
    }

    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

그리고 전화 :

BinaryOperator<TestObject> binary = TestObject::testInstance;

코드는 잘 컴파일됩니다. testInstance이중 하나 대신 단일 매개 변수로 호출하기 때문입니다 . 그래서 우리의 두 매개 변수는 어떻게 되었습니까? 출력하고 볼 수 있습니다.

public class TestObject {

    public TestObject() {
        System.out.println(this.hashCode());
    }

    public final TestObject testInstance(TestObject t){
        System.out.println("Test instance called. this.hashCode:" 
    + this.hashCode());
        System.out.println("Given parameter hashCode:" + t.hashCode());
        return t;
    }

    public final TestObject testInstance(TestObject t, TestObject t2){
        return t;
    }

    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

다음을 출력합니다.

 1418481495  
 303563356  
 Test instance called. this.hashCode:1418481495
 Given parameter hashCode:303563356

그래서 JVM은 param1.testInstance (param2)를 호출하기에 충분히 똑똑합니다. testInstance다른 리소스에서 사용할 수 있지만 TestObject 는 사용할 수 없습니다. 예 :

public class TestUtil {

    public final TestObject testInstance(TestObject t){
        return t;
    }
}

그리고 전화 :

BinaryOperator<TestObject> binary = TestUtil::testInstance;

컴파일되지 않고 컴파일러는 "TestUtil 유형은 testInstance (TestObject, TestObject)를 정의하지 않습니다 . "라고 말합니다 . 따라서 컴파일러는 동일한 유형이 아닌 경우 정적 참조를 찾습니다. 다형성은 어떻습니까? 최종 수정자를 제거하고 SubTestObject 클래스를 추가하면 :

public class SubTestObject extends TestObject {

    public final TestObject testInstance(TestObject t){
        return t;
    }

}

그리고 전화 :

BinaryOperator<TestObject> binary = SubTestObject::testInstance;

또한 컴파일되지 않으며 컴파일러는 여전히 정적 참조를 찾습니다. 그러나 아래 코드는 is-a 테스트를 통과하기 때문에 잘 컴파일됩니다.

public class TestObject {

    public SubTestObject testInstance(Object t){
        return (SubTestObject) t;
    }

}

BinaryOperator<TestObject> binary = TestObject::testInstance;

* 저는 공부하는 중이므로 시도해보고 알아 냈습니다. 틀 렸으면 언제든지 고쳐주세요.


java-8 Streams Reducer에서 간단한 작업은 두 개의 값을 입력으로 받아 계산 후 결과를 반환하는 함수입니다. 이 결과는 다음 반복에서 제공됩니다.

Math : max 함수의 경우 메서드는 전달 된 두 값의 최대 값을 계속 반환하며 결국 가장 큰 숫자를 가지고 있습니다.


이 소스가 매우 흥미 롭다는 것을 알았습니다 .

사실, 이중 콜론 으로 변하는 것은 람다 입니다 . 이중 콜론이 더 읽기 쉽습니다. 우리는 다음 단계를 따릅니다.

1 단계:

// We create a comparator of two persons
Comparator c = (Person p1, Person p2) -> p1.getAge().compareTo(p2.getAge());

2 단계:

// We use the interference
Comparator c = (p1, p2) -> p1.getAge().compareTo(p2.getAge());

3 단계 :

// The magic using method reference
Comparator c = Comparator.comparing(Person::getAge);

이전 Java 버전에서는 "::"또는 lambd 대신 다음을 사용할 수 있습니다.

public interface Action {
    void execute();
}

public class ActionImpl implements Action {

    @Override
    public void execute() {
        System.out.println("execute with ActionImpl");
    }

}

public static void main(String[] args) {
    Action action = new Action() {
        @Override
        public void execute() {
            System.out.println("execute with anonymous class");
        }
    };
    action.execute();

    //or

    Action actionImpl = new ActionImpl();
    actionImpl.execute();
}

또는 메소드에 전달 :

public static void doSomething(Action action) {
    action.execute();
}

그래서 저는 여기 솔직히 지나치게 복잡해진 수많은 답변을 봅니다.

대답은 매우 간단합니다. :: Method References https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html 이라고합니다.

따라서 복사-붙여 넣기를하지 않겠습니다. 링크에서 표로 스크롤하면 모든 정보를 찾을 수 있습니다.


이제 Method References가 무엇인지 간단히 살펴 보겠습니다.

A :: B 는 다음 인라인 람다 표현식을 다소 대체합니다 . (params ...)-> AB (params ...)

이것을 질문과 연관 시키려면 자바 람다 표현식을 이해하는 것이 필요합니다. 어렵지 않습니다.

인라인 람다 식은 정의 된 기능 인터페이스 (메서드가 1 개 이상없는 인터페이스 )와 유사합니다 . 내가 의미하는 바를 간단히 살펴 보겠습니다.

InterfaceX f = (x) -> x*x; 

InterfaceX는 기능적 인터페이스 여야합니다. 모든 기능적 인터페이스, 해당 컴파일러의 InterfaceX에서 중요한 것은 형식을 정의하는 것입니다.

InterfaceX는 다음 중 하나 일 수 있습니다.

interface InterfaceX
{
    public Integer callMe(Integer x);
}

아니면 이거

interface InterfaceX
{
    public Double callMe(Integer x);
}

또는 더 일반적인 :

interface InterfaceX<T,U>
{
    public T callMe(U x);
}

첫 번째로 제시된 사례와 앞서 정의한 인라인 람다 식을 살펴 보겠습니다.

Java 8 이전에는 다음과 같이 유사하게 정의 할 수있었습니다.

 InterfaceX o = new InterfaceX(){
                     public int callMe (int x, int y) 
                       {
                        return x*x;
                       } };

기능적으로도 마찬가지입니다. 차이점은 컴파일러가 이것을 인식하는 방법에 더 있습니다.

이제 인라인 람다 식을 살펴 보았으므로 메서드 참조 (: :)로 돌아 갑시다. 다음과 같은 수업이 있다고 가정 해 보겠습니다.

class Q {
        public static int anyFunction(int x)
             {
                 return x+5;
             } 
        }

anyFunctions 메소드 는 InterfaceX callMe 와 동일한 유형을 갖기 때문에이 둘을 메소드 참조와 동등하게 만들 수 있습니다.

다음과 같이 작성할 수 있습니다.

InterfaceX o =  Q::anyFunction; 

그리고 이것은 다음과 같습니다.

InterfaceX o = (x) -> Q.anyFunction(x);

메서드 참조의 멋진 점과 장점은 처음에는 변수에 할당 할 때까지 유형이 없다는 것입니다. 따라서 동등하게 보이는 (동일하게 정의 된 유형이 있음) 기능 인터페이스에 매개 변수로 전달할 수 있습니다. 귀하의 경우에는 정확히 어떤 일이 발생합니까?


이전 답변은 ::메서드 참조가 수행 하는 작업에 대해 매우 완벽 합니다. 요약하면 메서드 (또는 생성자)를 실행하지 않고 참조 할 수있는 방법을 제공하며 평가시 대상 유형 컨텍스트를 제공하는 기능 인터페이스의 인스턴스를 만듭니다.

다음은 메서드 참조를 ArrayList사용하지 않고 WITH 에서 최대 값을 가진 개체를 찾는 두 가지 예 ::입니다. 설명은 아래 주석에 있습니다.


사용하지 않고 ::

import java.util.*;

class MyClass {
    private int val;
    MyClass (int v) { val = v; }
    int getVal() { return val; }
}

class ByVal implements Comparator<MyClass> {
    // no need to create this class when using method reference
    public int compare(MyClass source, MyClass ref) {
        return source.getVal() - ref.getVal();
    }
}

public class FindMaxInCol {
    public static void main(String args[]) {
        ArrayList<MyClass> myClassList = new ArrayList<MyClass>();
        myClassList.add(new MyClass(1));
        myClassList.add(new MyClass(0));
        myClassList.add(new MyClass(3));
        myClassList.add(new MyClass(6));

        MyClass maxValObj = Collections.max(myClassList, new ByVal());
    }
}

사용하여 ::

import java.util.*;

class MyClass {
    private int val;
    MyClass (int v) { val = v; }
    int getVal() { return val; }
}

public class FindMaxInCol {
    static int compareMyClass(MyClass source, MyClass ref) {
        // This static method is compatible with the compare() method defined by Comparator. 
        // So there's no need to explicitly implement and create an instance of Comparator like the first example.
        return source.getVal() - ref.getVal();
    }

    public static void main(String args[]) {
        ArrayList<MyClass> myClassList = new ArrayList<MyClass>();
        myClassList.add(new MyClass(1));
        myClassList.add(new MyClass(0));
        myClassList.add(new MyClass(3));
        myClassList.add(new MyClass(6));

        MyClass maxValObj = Collections.max(myClassList, FindMaxInCol::compareMyClass);
    }
}

이중 콜론 즉 ::연산자는 Java 8에서 메소드 참조 로 도입되었습니다 . 메서드 참조는 기존 메서드를 이름으로 참조하는 데 사용되는 람다 식 의 한 형태입니다 .

classname :: methodName

전의:-

  • stream.forEach(element -> System.out.println(element))

Double Colon을 사용하여 ::

  • stream.forEach(System.out::println(element))

참고 URL : https://stackoverflow.com/questions/20001427/double-colon-operator-in-java-8

반응형