Java가 왜 형식 유추를하지 않습니까?


44

나는 언어가 언어이고 VM이 매우 성숙하다는 점에서 Java가 왜 형식 유추를하지 않는지 항상 궁금했습니다. Google의 Go는 형식 유추가 뛰어난 언어의 한 예이며 입력해야하는 양을 줄입니다. 이 기능 뒤에 Java의 일부가 아닌 특별한 이유가 있습니까?


3
Java만큼 오래되고 대중적인 언어의 하위 호환성 규칙
ratchet freak

9
@ratchetfreak 형식 유추를 이전 버전과 호환되는 방식으로 추가 할 수 없습니까? 오래된 프로그램은 필요한 것보다 더 많은 유형 정보를 제공합니다.

1
Type Erasure와 함께 사용하면 의도하지 않은 효과가있을 수 있습니다. docs.oracle.com/javase/tutorial/java/generics/…
재커리 예이츠

4
Java 8은 Lambda 기능을 사용 하여 많은 유형 유추를 가져옵니다 . 유형과 유추되는 모든 것을 언급하지 않고도 복잡한 람다를 작성할 수 있습니다.
Joachim Sauer

4
지역 변수 유형 추론이 Java로 제공됩니다. JEP 286 : 지역 변수 유형 추론
Jimmy 페이지

답변:


60

기술적으로 말하면 Java는 제네릭을 사용할 때 형식 유추를 가지고 있습니다 . A의 일반적인 방법 과 같은

public <T> T foo(T t) {
  return t;
}

컴파일러는 작성시 분석하고 이해합니다.

// String
foo("bar");
// Integer
foo(new Integer(42));

인수로 입력 된 내용에 따라 첫 번째 호출에 대해서는 문자열이 리턴되고 두 번째 호출에 대해서는 정수가 리턴됩니다. 결과적으로 적절한 컴파일 타임 검사를 받게됩니다. 할 때 또한 자바 7에서, 하나는 추론 몇 가지 추가 유형을 얻을 수있는 인스턴스 제네릭이 너무 좋아

Map<String, String> foo = new HashMap<>();

Java는 우리를 위해 빈 꺾쇠 괄호를 채울만큼 친절합니다. Java가 왜 변수 할당의 일부로 타입 추론 을 지원하지 않습니까? 한 시점 에서 변수 선언에 형식 유추에 대한 RFE 가 있었지만 "수정하지 않음"으로 닫혔습니다.

인간은 두 가지 방식으로 형식 선언의 중복성으로부터 혜택을받습니다. 먼저, 중복 유형은 유용한 문서 역할을합니다. 독자는 getMap () 선언을 검색하여 반환되는 유형을 찾을 필요가 없습니다. 둘째, 이중화를 통해 프로그래머는 의도 된 유형을 선언 할 수 있으므로 컴파일러가 수행 한 교차 점검의 이점을 얻을 수 있습니다.

이것을 닫은 기고자는 또한 그것이 "비자 바와 같지 않다"고 느끼며 이것이 내가 동의하는 것이라고 언급했다. 자바의 장황함은 축복이자 저주가 될 수 있지만 언어를 그대로 만들어줍니다.

물론 그 특정 RFE는 그 대화의 끝이 아니 었습니다. Java 7 동안이 기능은 다시 고려 되었으며 James Gosling의 테스트 구현을 포함하여 일부 테스트 구현이 작성되었습니다. 다시 말하지만이 기능은 결국 중단되었습니다.

Java 8이 출시되면서 이제 람다의 일부로 형식 유추를 얻습니다.

List<String> names = Arrays.asList("Tom", "Dick", "Harry");
Collections.sort(names, (first, second) -> first.compareTo(second));

자바 컴파일러 방법을보고 할 수있는 Collections#sort(List<T>, Comparator<? super T>)다음의 인터페이스 Comparator#compare(T o1, T o2)및 그 결정 firstsecondA가되어야 String하므로 프로그래머 람다 표현 유형을 재 작성하는 것을 포기 수.


5
First, the redundant type serves as valuable documentation - readers do not have to search for the declaration of getMap() to find out what type it returns-예, 그렇다면 HashMap<String, Integer> map = foo.getMap()동의합니다-C #에서는 일반적으로 var그러한 경우에는 사용할 수는 없지만 사용하지 않습니다 . 그러나이 논쟁은 물이라면 물을 보유하지 않습니다 HashMap<String, Integer> map = new HashMap<String, Integer>(). 이것은 진정한 중복성이며 유형 이름을 두 번 쓰면 아무런 이점이 없습니다. 그리고 컴파일러 교차 검사를 통해 어떻게 이점을 얻을 수 있는지 전혀 이해하지 못합니다.
Konrad Morawski

9
그렇습니다. 제네릭에는 좋지만 varJava 의 C #과 동일한 내용이 여전히 누락 되었습니다.
Konrad Morawski

15
)은 "유엔 - 자바 같은"존재에 관해서는,이 (치즈) 이야기는 마음에 오는 9gag.com/gag/2308699/-this-is-how-things-are-done-around-here
콘라드 Morawski

6
또한 함수의 반환 유형은 종종 명백하거나 불필요하며 IDE가 아닌 경우에도 IDE가 0.5 초 안에 유형을 플래그 지정할 수 있습니다.
Phoshi

8
공식 인용문 Humans benefit from the redundancy은 현재 질문에 대한 실제 답변 이라고 생각합니다. 내가 읽은 모든 정당화는 Java 디자이너의 무례하고 근거가 없으며 우스운 변명처럼 보입니다 .C # 및 C ++에는 기능이 있으며 C # 및 C ++ 디자이너는 Java와 모든 사람이 행복하게 사용합니다. Java 개발자가 C # 또는 C ++ 개발자와 다른 이유는 무엇입니까? 이것이 제가 @KonradMorawski에 동의하는 이유입니다. "여기에서 일이 이루어지는 방식"이 다시 실제적인 이유 인 것 같습니다 .
paercebal

16

먼저, 형식 유추는 런타임이 30 년 된 CPU인지 또는 새로운 비트인지 여부에 관계없이 런타임의 성숙도와 는 아무런 관련없습니다 . 컴파일러에 관한 것입니다.

즉, 제네릭에 허용되며 제네릭이 아닌 유형에 허용되지 않는 이유는 철학 때문인 것으로 보입니다. 디자이너가 추가하지 못하게하는 것은 없습니다.

업데이트 : java 10에서 지원하는 것 같습니다 —- http://openjdk.java.net/jeps/286


5

내가 아는 한, Java가 90 년대 초에 설계되었을 때 형식 추론은 주류 언어들 사이에서 인기가 없었지만 (ML과 같이 이미 잘 알려진 개념이었습니다). 따라서 Java가 C ++, Pascal 또는 기타 주류 언어를 사용하지 않는 프로그래머를 대상으로하기 때문에 유형 유추가 지원되지 않았다고 생각할 수 있습니다 (최소한의 놀람 원칙).

또한 Java의 디자인 원칙 중 하나는 프로그래머와 컴파일러가 코드에 대해 동일한 이해를 갖도록 명시 적으로 작성하는 것입니다. 정보를 복제하면 오류 가능성이 줄어 듭니다. 물론 더 많은 문자를 입력하는 것이 제공하는 추가 안전성의 가치가 있는지 여부는 맛의 문제 일 수 있지만 이것은 Java에 대한 디자인 철학이었습니다.

Java가 미래에 유형 유추를 얻을지 모르겠지만 IMO는 언어에 큰 혁명이 될 것입니다 (Glenn Nelson이 언급했듯이 "Java와 유사하지 않음"으로 설명 됨). 새로운 이름을 선호하는 Java 이름.

유형 유추와 함께 JVM 언어를 사용하려면 Scala를 사용할 수 있습니다.


2

몇 가지 가능한 이유를 생각할 수 있습니다. 하나는 명시 적 타이핑이 자체 문서화라는 것입니다. Java는 일반적으로 이것을 결정보다 우선 순위로 만듭니다. 또 다른 이유는 유형이 다소 모호한 경우 일 수 있습니다. 유형 또는 하위 유형이 루틴을 만족시킬 수있는 경우와 같습니다. List를 사용하고 싶지만 누군가가 와서 ArrayList 전용 메소드를 사용한다고 가정 해 봅시다. JIT는 ArrayList를 유추하고 컴파일 오류를 원하더라도 계속 수행합니다.


8
GridBagLayout gridbag = new GridBagLayout (); 자체 문서에 추가 하시겠습니까? 순수한 반복.
Anders Lindén

3
두 유형이 동일하지 않은 경우를 명확하게합니다. 서브 클래스의 인스턴스를 쉽게 지정할 수 있습니다.
jiggy

Let's say you want to use a List, but someone comes along and uses a method exclusive to ArrayList. The JIT would infer an ArrayList and carry on even if you wanted a compilation error-나는이 비트를 이해하지 못한다. 타입 추론은 변수를 메소드를 호출하지 않고 변수를 설명하는 순간에 발생합니다. 당신이 의미 한 바의 예를 보여줄 수 있습니까?
Konrad Morawski

2
@ KononMorawski : 메소드가 ArrayList를 반환하면 유형이 유추된다는 것을 의미한다고 가정합니다. 타입을 리턴 타입 이외의 것으로 취급하려면 추론을 사용할 수 없습니다. 그래도 제정신이 아닌 곳의 코드베이스에서 이것이 어떻게 문제가 될 수 있는지 이해하지 못합니다.
Phoshi

JIT는 형식 유추에 전혀 영향을 미치지 않습니다. 형식 유추는 컴파일 타임 현상입니다. 변수가 List에 대한 참조로 선언되면 ArrayList 멤버에 액세스하려고하면 check를 입력하지 않고 컴파일 오류가 발생합니다.
sara

0

요구 사항에 맞는 가장 일반적인 인터페이스를 사용하여 변수를 선언하고 다음과 같이 적절한 구현 클래스로 변수를 초기화하라는 잘 확립 된 권장 사항과 모순됩니다.

Collection<String> names = new ArrayList<>();

효과적으로,

var names = new ArrayList<String>();

구문 설탕에 불과합니다

ArrayList<String> names = new ArrayList<String>();

원하는 경우 IDE에서 new ArrayList<String>()"원 클릭"(리 팩터 / 로컬 변수 작성)을 사용 하여 표현식 에서 생성 할 수 있지만 "인터페이스 사용"권장 사항과 모순된다는 점을 기억하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.