본문 바로가기
java

[java] 이중 콜론 연산자 ::

by socialcomputer 2021. 9. 12.
반응형

이중 콜론 연산자 (Double Colon Operator) 람다(Lamda)식과 함께 살펴보려고 한다. 

 

  • 람다식과 이중 콜론 연산자를 이용하면 간결하게 표현할 수 있는데, 예를 들어 comparator를 생성해보자
#1 lamda
Comparator c = (Computer c1, Computer c2) -> { c1.getAge().compareTo( c2.getAge() ) };
#2 lamda
Comparator c = (c1, c2) -> { c1.getAge().compareTo( c2.getAge() };

#3 ::
Comparator c = Comparator.comparing(Computer::getAge());

위에 두 람다식보다 이중콜론 연산자가 훨씩 읽기 쉽고 짧게 표현할 수 있다. 

 

  • 이전에는 java에서 아래와 같이 inner class를 이용해 구현해야 했다.
Comparartor<Computer> abstractInnerClass = new Comparator<Computer>(){
		@Override
        public int compareTo(Computer c1, Computer c2){
        	return c1.getAge().compareTo(c2.getAge());        
        }
}

 

  • :: 사용법

사용법은 targetReference :: methodName  즉 타겟레퍼런스 :: 메소드명  =  Computer::getAge;

(이름만으로 특정 메소드를 호출할 수 있도록 :: 연산자를 사용)

함수를 참조하고 있다는 것과 함수의 인자가 정확해야 한다는 것에 주목해야 한다. 

#!
Computer::getAge;
#2
Function<Computer, Integer> getAge = Computer::getAge();
Integer ComputerAge = getAge.apply(c1);

[#2 코드]  getAge는 Computer의 getAge()함수를 호출하는데, getAge에 c1을 적용하면

컴퓨터 c1의 getAge()메소드를 호출해 age를 반환한다. ?

 

  • 이중콜론을 사용할 수있는 여러 방법들이 있다. (Method Reference)

  1. 정적 메소드 static utility method

#ComputerUtils 의 repair 가 정적 메소드라고 가정하고

List inventory = Arrays.asList(
			new Computer( 2015, "white", 35), new Computer(2009, "black", 65));
            
inventory.forEach(ComputerUtils::repair);

  2. 기존 객체의 인스턴스 메소드 an Instance Method of an Existing Method

'기존 객체의 인스턴스의 메소드를 참조하는 흥미로운 예제' 를 보자 

Computer c1 = new Computer(2015, "white");
Computer c2 = new Computer(2009, "black");
Computer c3 = new Computer(2014, "black");
Arrays.asList(c1, c2, c3).forEach(System.out::print);

 java 에 이미 정의된 기존 객체의 인스턴스(System.out) 의 메소드(print) 를 호출하기도 한다. 

더보기
출처-http://wiki.sys4u.co.kr/pages/viewpage.action?pageId=7766725  
출처-http://wiki.sys4u.co.kr/pages/viewpage.action?pageId=7766725  

 

  3. 새로 생성한 객체의 인스턴스 메소드 an Instance Method of an Arbitrary Object of a Particular Type

Computer c1 = new Computer(2015, "white", 100);
Computer c2 = new MacbookPro(2009, "black", 100);
List inventory = Arrays.asList(c1, c2);
inventory.forEach(Computer::turnOnPc);

 사용자가 정의한 Computer라는 클래스의 turnOnPc 메소드를 호출할 수도 있다.

특정 인스턴스가 아니라 유형 자체(Computer) 에서 turnOnPc 메소드를 참조하고 있다

4행에서 인스턴스 메소드 turnOnPc  인벤토리의 모든 개체에 대해 호출된다. 

그리고 이것은 자연스럽게 – c1의 경우 turnOnPc 메서드 가 Computer 인스턴스 에서 호출되고 c2의 경우 MacbookPro 인스턴스 에서 호출 됨을 의미 합니다.

 

  4. 특정 개체의 슈퍼 메소드

Computer(super class)에 calculateValue라는 메소드가 있다고 가정하자.

public Double calculateValue(Double initialValue) {
    return initialValue/1.50;
}

그리고 MacbookPro(sub class) 에서 calculateValue를 재정의 해보자.

@Override
public Double calculateValue(Double initialValue){
    Function<Double, Double> function = super::calculateValue;
    Double pcValue = function.apply(initialValue);
    return pcValue + (initialValue/10) ;
}

MacbookPro 인스턴스에서 calculateValue 메소드를 호출하면, Computer(super class)의 calculateValue도 호출될 것이다.

타겟 메소드에 클래스이름이 아닌 super 도 올 수 있다는 것을 의미한다. 

macbookPro.calculateValue(999.99);

 

  • 구조 참조 Constructor Reference

 1. 새로운 인스턴스 생성하기

객체를 인스턴스화 하는 생성자를 참조할 수도 있는데 매우 간단하다. 

@FunctionalInterface
public interface InterfaceComputer{
	/*public abstract*/ Computer create();
}

InterfaceComputer c = Computer::new;
Computer computer = c.create();

생성자에서 두개의 파라미터를 가지는 경우는 다음처럼 하면 된다.

BiFunction<Integer, String, Computer> c4Function = Computer::new;
Computer c4 = c4Function.apply(2013, "white");

생성자가 세개 이상의 파라미터를 가지는 경우는 새로운 Functional interface를 정의해줘야 한다.

@FunctionalInterface
interface TriFunction<A, B, C, R> {
    R apply(A a, B b, C c);
    default <V> TriFunction<A, B, C, V> andThen( Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (A a, B b, C c) -> after.apply(apply(a, b, c));
    }
}

  2. 배열 생성하기

5개의 Computer 객체의 배열을 만들 수도 있다.

Function <Integer, Computer[]> computerCreator = Computer[]::new;
Computer[] computerArray = computerCreator.apply(5);

 

 

아직 내가 잘 활용할 수 있을 지 모르겠지만, 이중콜론이 무엇인지 어떤 식으로 사용하는 지 알게 되었다. 특히  stream을 활용 할때 좋다고 하니 평소에 문자열이 다루기 까다롭다고 생각했던 입장에선 얼른 적용시켜봐야겠다는 생각이 든다. 
참고로 funtional interface를 포함한 interface에 관한 설명도 올릴 예정이다. 

 

 

참고

https://www.baeldung.com/java-8-double-colon-operator

http://wiki.sys4u.co.kr/pages/viewpage.action?pageId=7766725 

 

http://wiki.sys4u.co.kr/pages/viewpage.action?pageId=7766725

페이지 … PLATEER OPEN WIKI Programming Tips JSDK 배너의 맨 끝으로 배너의 맨 처음으로 이중 콜론 연산자 메타 데이터의 끝으로 건너뛰기 수진 이님이 작성, 9월 20, 2017에 최종 변경 메타 데이터의 시작

wiki.sys4u.co.kr

 

반응형

댓글