: :( 이중 콜론) 연산자 (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
위는 기능적 인터페이스 입니다. 을 완전히 이해하려면 ::
기능적 인터페이스도 이해하는 것이 중요합니다. 분명히 기능적 인터페이스 는 하나의 추상 메소드 만있는 인터페이스입니다.
기능 인터페이스의 예로 Runnable
는 Callable
, 및 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
. Supplier 의 get
메서드 는 값을 반환하지만 인수를 사용하지 않습니다. 따라서 이로 인해 오류가 발생합니다.
메소드 참조는 기능 인터페이스의 메소드를 나타냅니다. (언급했듯이 기능 인터페이스는 각각 하나의 메서드 만 가질 수 있습니다.)
더 많은 예 : Consumer 의 accept
메서드 는 입력을 받지만 아무것도 반환하지 않습니다.
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;
메서드 참조는 다른 스타일을 가질 수 있지만 기본적으로 모두 동일한 의미를 가지며 간단히 람다로 시각화 할 수 있습니다.
- 정적 메서드 (
ClassName::methName
) - 특정 개체 (
instanceRef::methName
) 의 인스턴스 메서드 - 특정 개체의 슈퍼 메서드 (
super::methName
) - 특정 유형 (
ClassName::methName
) 의 임의 개체의 인스턴스 메서드 - 클래스 생성자 참조 (
ClassName::new
) - 배열 생성자 참조 (
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
'programing' 카테고리의 다른 글
Android 레이아웃 파일에서 "tools : context"는 무엇입니까? (0) | 2020.09.28 |
---|---|
Java 클래스에서 표준 이름, 단순 이름 및 클래스 이름의 차이점은 무엇입니까? (0) | 2020.09.28 |
드로어 블을 비트 맵으로 변환하는 방법은 무엇입니까? (0) | 2020.09.28 |
생성자와 ngOnInit의 차이점 (0) | 2020.09.28 |
Swift의 #pragma 마크? (0) | 2020.09.28 |