Java의 새로운 기능

Java 10의 새로운 기능 - 지역변수 타입 추론

늦깎이_개발자 2021. 9. 23. 20:17
반응형

1. 지역변수 타입 추론

 Java 10에서 가장 눈에 띄는 변화 중 하나는 초기화를 통한 지역변수 타입 추론이다. 자바 9까지는 지역 변수의 타입을 명시해야 했으며, 그것이 오른쪽에 대입되는 객체와 호환이 가능한지를 확인해야 했다.

String message = "Good bye, Java 9";

 자바 10부터는 다음과 같이 지역변수를 선언할 수 있다.

@Test
public void whenVarInitWithString_thenGetStringTypeVar() {
    var message = "Hello, Java 10";
    assertTrue(message instanceof String);
}

 위에서는 message에 타입을 명시하지 않는다. 대신 var로 표시하고, 컴파일러는 오른쪽에 대입되는 객체를 통해 message의 타입을 추론한다. 위의 예시에서 message의 타입은 String일 것이다. 

 

 이 기능은 초기화가 되는 지역 변수에만 사용할 수 있다. 멤버 변수, 메서드 매개 변수, 반환형 등에 사용할 수 없으며, 컴파일러가 타입을 추론할 수 있게 하기 위해 초기화가 필요하다.

 이 기능은 보일러플레이트 코드를 줄이는데 도움을 준다.

Map<Integer, String> map = new HashMap<>(); // Before Java 10
var idToNameMap = new HashMap<Integer, String>(); // Java 10

 이것은 변수의 타입보다 변수명에 더 집중하는데도 도움을 준다.

 

 주의할 점 중 하나는, var는 키워드가 아니라는 것이다. 이는 'var'를 변수명이나 함수명 등에 이미 사용하여 구현된 프로그램들에 대한 하위 호환성을 보장해준다. var는 int와 마찬가지로 예약어이다.

 또한 var을 사용한다고 해서 런타임에 오버헤드가 발생하지 않으며, 자바가 동적 타입 언어가 된 것도 아니라는 것을 기억해야 한다. 변수의 타입은 컴파일 타임에 추론되며, 나중에 바뀔 수 없다.

 

2. var의 잘못된 사용

 이미 언급했듯이, var은 초기화되지 않는 지역 변수에는 사용될 수 없다.

var n; // error: cannot use 'var' on variable without initializer

 

null로 초기화할 수도 없다. null을 통한 타입 추론이 불가능하기 때문이다.

var emptyList = null; // error: variable initializer is 'null'

 

 

 var은 지역변수에만 사용 가능하다. 멤버 변수 등에는 사용이 불가능하다.

class Hello {
    public var = "hello"; // error: 'var' is not allowed here
}

 

 람다 식의 경우, 명시적인 타겟 타입이 필요하다. 따라서 var 사용이 불가능하다.

var p = (String s) -> s.length() > 10; // error: lambda expression needs an explicit target-type

 

 아래와 같이 배열을 사용하는 경우에도 사용할 수 없다.

var arr = { 1, 2, 3 }; // error: array initializer needs an explicit target-type

 

3. var 사용 가이드라인

 var를 사용하는 것이 가능은 하지만, 사용하는 것이 별로 좋은 선택이 아닌 경우가 있다. 예를 들면 가독성을 떨어뜨리는 경우다.

var result = obj.prcoess();

 

 위에서는 process() 메서드에 의해 반환되는 객체의 타입을 이해하는 것이 쉽지 않으므로 가독성이 떨어진다. 

 우리가 이 기능을 어떻게 사용해야할 지에 대한 가이드라인이 있다. 여기를 클릭하면 확인할 수 있다. 

 

 긴 파이프라인을 가진 스트림을 사용할 때도 var 사용을 피해야 한다. 

var x = emp.getProjects.stream()
  .findFirst()
  .map(String::length)
  .orElse(0);

 

 또한 var 사용은 예상하지 못하는 결과를 가져올 수 있다.

 예를 들면, 아래와 같이 다이아몬드 연산자를 써보자.

var empList = new ArrayList<>();

 empList의 타입은 List<Object>가 아닌 ArrayList<Object>가 될 것이다. 만약 ArrayList<Employee>로 명시하고 싶다면 아래와 같이 하면 된다.

var empList = new ArrayList<Employee>();

 

 또한 다음과 같은 경우에도 예상치 못한 에러가 발생할 수 있다.

@Test
public void whenVarInitWithAnonymous_thenGetAnonymousType() {
    var obj = new Object() {};
    assertFalse(obj.getClass().equals(Object.class)); // false
    obj = new Object() // error!!
}

  obj에 new Object()를 대입할 수 없다. 왜냐하면 obj의 타입은 Object가 아니라 Object를 확장한 익명클래스이기 때문이다.

 

※ 참조

https://www.baeldung.com/java-10-local-variable-type-inference

반응형