JDK 7 : 다이아몬드 오퍼레이터

Project Coin은 새로운 JDK 7 기능의 하위 집합으로 수많은 "작은 언어 향상"을 제공합니다. 저는 최근에 Project Coin의 Strings 전환에 대해 블로그에 올렸으며이 게시물에서는 새로운 Diamond Operator ( )에 대해 씁니다 .

Diamond 연산자는 컴파일러가 제네릭 클래스의 생성자에 대한 매개 변수 유형을 추론하도록함으로써 제네릭을 둘러싼 Java의 자세한 정보를 줄입니다. Diamond Operator를 Java 언어에 추가하기위한 원래 제안은 2009 년 2 월에 작성되었으며 다음과 같은 간단한 예를 포함합니다.

예를 들어, 다음 지정 문을 고려하십시오.

지도 anagrams = 새로운 HashMap ();

이것은 다소 길기 때문에 다음으로 대체 할 수 있습니다.

지도 anagrams = new HashMap ();

Jeremy Manson의 제안 (Project Coin 아이디어 요청에 대한 첫 번째 제안 중 하나)에 제공된 위의 예는 간단하지만 Diamond Operator가 JDK 7에 적용되는 방법을 적절하게 보여줍니다. Manson의 제안은 또한이 추가 이유에 대해 중요한 정보를 제공합니다. 바람직했습니다.

유형 매개 변수가 불필요하게 복제되어야하는 요구 사항

이것은 불행한

정적 팩토리 메서드의 과잉, 단순히 유형 추론 때문에

메서드 호출에서 작동합니다.

즉, JDK 7 Project Coin에 Diamond Operator를 추가하면 메서드에서 사용할 수있는 생성자에 유형 추론이 제공됩니다. 메서드를 사용하면 명시 적 매개 변수 유형 사양에서 벗어날 때 암시 적으로 유형 추론이 수행됩니다. 반면에 인스턴스화를 사용하는 경우 컴파일러에 유형을 유추하도록 "알리기"위해 다이아몬드 연산자를 명시 적으로 지정해야합니다.

Manson은 원래 제안에서 특별한 다이아몬드 연산자가없는 구문은 인스턴스화를위한 유형을 암시 적으로 추론하는 데 사용할 수 없다고 지적했습니다. "이전 버전과의 호환성을 위해 new Map ()은 원시 유형을 나타내므로 유형에 사용할 수 없기 때문입니다. 추론." Java 자습서의 Java 언어 학습 과정의 Generics Lesson의 Type Inference 페이지에는 Java SE 7을 반영하도록 이미 업데이트 된 "Type Inference and Instantiation of Generic Classes"라는 섹션이 포함되어 있습니다.이 섹션에서는 인스턴스화에서 유형 유추를 사용하도록 컴파일러에 명시 적으로 알리려면 연산자를 지정해야합니다.

제네릭 클래스 인스턴스화 중에 자동 유형 추론을 활용하려면 다이아몬드 연산자를 지정해야합니다. 다음 예제에서 컴파일러는 HashMap () 생성자가 Map이 아닌 HashMap 원시 유형을 참조하기 때문에 확인되지 않은 변환 경고를 생성합니다. 유형

효과적인 자바 제 2 판의 항목 24 ( "확인되지 않은 경고 제거")에서 Josh Bloch는 굵은 텍스트로 "확인되지 않은 모든 경고 제거"를 강조 합니다. Bloch는 선언 오른쪽에 원시 유형을 사용하는 코드를 컴파일 할 때 발생하는 확인되지 않은 변환 경고의 예를 보여줍니다. 다음 코드 목록은이 경고를 발생시키는 코드를 보여줍니다.

final Map
     
       statesToCities = new HashMap(); // raw! 
     

다음 두 화면 스냅 샷은 위의 코드 줄에 대한 컴파일러의 응답을 보여줍니다. 첫 번째 이미지는 사용 가능한 -Xlint 경고가 없을 때 메시지를 표시하고 두 번째 이미지는 -Xlint:uncheckedjavac에 대한 인수로 제공 될 때 발생하는보다 명시적인 경고를 보여줍니다 .

경우 효과적인 자바 , 블로흐이 특정되지 않은 경고가 명시 적으로 제네릭 클래스의 인스턴스에 매개 변수 유형을 제공하여 주소 쉽다는 것을 지적한다. JDK 7을 사용하면이 작업이 훨씬 쉬워집니다! 이러한 유형 이름을 가진 명시 적 텍스트를 추가 할 필요없이 유형은 많은 경우에 유추 될 수 있으며 다이아몬드 연산자의 사양은 원시 유형을 사용하는 대신이 추론을 수행하도록 컴파일러에 지시합니다.

다음 Java 코드 목록은 이러한 개념에 대한 단순한 예를 제공합니다. 원시 Set의 인스턴스화, 매개 변수 유형의 명시 적 사양을 사용한 Set의 인스턴스화 및 다이아몬드 연산자 ( ) 의 사양으로 인해 추론 된 매개 변수 유형을 사용한 Set의 인스턴스화를 보여주는 메서드가 있습니다 .

package dustin.examples; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import static java.lang.System.out; /** * Very simple demonstration of JDK 7's/Project Coin's "Diamond Operator." */ public class DiamondOperatorDemo { /** Use of "raw" type. */ private static Set rawWithoutExplicitTyping() { final Set names = new HashSet(); addNames(names); return names; } /** Explicitly specifying generic class's instantiation parameter type. */ private static Set explicitTypingExplicitlySpecified() { final Set names = new HashSet(); addNames(names); return names; } /** * Inferring generic class's instantiation parameter type with JDK 7's * 'Diamond Operator.' */ private static Set explicitTypingInferredWithDiamond() { final Set names = new HashSet(); addNames(names); return names; } private static void addNames(final Set namesToAddTo) { namesToAddTo.add("Dustin"); namesToAddTo.add("Rett"); namesToAddTo.add("Homer"); } /** * Main executable function. */ public static void main(final String[] arguments) { out.println(rawWithoutExplicitTyping()); out.println(explicitTypingExplicitlySpecified()); out.println(explicitTypingInferredWithDiamond()); } } 

위의 코드가 컴파일되면 "원시"케이스 만 경고로 이어집니다.

이 시점에서 javap가이 세 가지 방법에 대해 알려주는 내용을 살펴 보는 것은 통찰력이있을 수 있습니다. 이 경우 다음 명령을 사용하여 수행됩니다 ( -vverbose 옵션은 모든 -p육즙 세부 ​​정보를 제공하고 private메서드에 대한 이러한 육즙 세부 ​​정보를 표시 합니다).

javap -v -p -classpath classes dustin.examples.DiamondOperatorDemo 

이러한 메서드는 모두 단일 클래스에 있었기 때문에 전체 클래스에 대한 단일 출력 스트림이 있습니다. 그러나 비교하기 쉽도록 출력을 잘라내어 각 메소드에 대한 javap 출력을 서로 정렬하는 형식으로 붙여 넣었습니다. 각 열은 javap메서드 중 하나에 대한 출력을 나타냅니다 . 특정 메서드의 글꼴 색상을 파란색으로 변경하여 눈에 띄게 만들고 해당 열의 출력에 레이블을 지정했습니다.

메소드 자체의 이름 외에 javap출력 에는 차이가 없습니다 . 이는 Java 제네릭 유형 삭제가 런타임에 유형에 따른 차별화를 사용할 수 없음을 의미하기 때문입니다. Generics에 대한 Java Tutorial에는이를 설명하는 Type Erasure라는 페이지가 포함되어 있습니다.

컴파일러는 컴파일 타임에 실제 형식 인수에 대한 모든 정보를 제거합니다.

새 코드가 레거시 코드와 계속해서 인터페이스 할 수 있도록 유형 삭제가 존재합니다. 다른 이유로 원시 유형을 사용하는 것은 잘못된 프로그래밍 관행으로 간주되며 가능하면 피해야합니다.

위의 인용문에서 알 수 있듯이 삭제는 원시 유형을 바이트 코드화하는 것이 명시 적으로 유형이 지정된 매개 변수 유형과 다르지 않지만 개발자가 레거시 코드와 통합하는 것을 제외하고 원시 유형을 사용하지 않도록 장려한다는 것을 의미합니다.

결론

Java SE 7에 다이아몬드 연산자 ( )가 포함 된 것은 일반 클래스를 인스턴스화하는 코드가 덜 장황 할 수 있음을 의미합니다. 일반적으로 코딩 언어, 특히 Java는 명시적인 사양을 요구하기보다는 구성에 대한 관습, 예외에 의한 구성 및 가능한 한 자주 추론과 같은 아이디어로 이동하고 있습니다. 동적 유형 언어는 유형 추론으로 잘 알려져 있지만 정적으로 유형이 지정된 Java조차도 이보다 더 많은 작업을 수행 할 수 있으며 다이아몬드 연산자가 그 예입니다.

//marxsoftware.blogspot.com/에서 사용 가능한 원본 게시물

이 이야기 "JDK 7 : The Diamond Operator"는 원래 JavaWorld에 의해 출판되었습니다.