LichKing
15k
2020-02-07 16:38:44
12
3184

JDK 14 기능정리


올 3월 GA 예정인 jdk 14 의 몇가지 기능들을 정리해봤습니다.

아래는 블로그글 그대로 가져오는거라 포맷이 좀 다를 수 있습니다.

원글: https://multifrontgarden.tistory.com/265

------------------------------------------------------------

2020년 3월 17일 GA 예정인 JDK 14 의 몇가지 피처들을 정리해본다.


Pattern Matching for instanceof (Preview)

런타임에 객체의 타입을 확인하는 instanceof 연산자는 보통 아래와같은 관용구(idiom)로 많이 사용된다.

if(obj instanceof String) {
  String s = (String) obj;
}

이 instanceof 연산자를 확장하여 아래와같은 문법을 지원한다.

if(obj instanceof String s) {
  // String 타입의 s 변수 사용
}

코틀린에 대한 경험이 있는 사람이라면 바로 느꼈겠지만 코틀린의 스마트 캐스팅과 유사한 문법으로 보인다. 다만 한가지 좀 이해하기 어려운 스펙이 있는데

if (obj instanceof String s){                 
    System.out.println(s.startsWith("h"));  
} else {                                     
    System.out.println(s);                  
}                                           

if 문이 false 인 경우에도 else 블럭에서 s 에 대한 이용이 가능하다. 다만 이 경우에는 obj가 String 타입이 아니므로 obj 를 캐스트해서 사용하는게 아니라 해당 클래스의 필드를 참조하게된다.

public class First {
    private String s = "hello";

    public void test() {
        Object o = 123;

        if (o instanceof String s){
            System.out.println(s);
        } else {
            System.out.println(s);
        }
    }
}

이 경우 else 블럭에서 s 는 인스턴스 필드 s 를 참조하게되며 인스턴스 필드에 s 가 존재하지않는 경우 컴파일 되지않는다. 인스턴스 필드 s 가 존재하지않더라도 else 블럭에서 s 를 이용하지않는다면 컴파일은 된다. 메서드가 static 일경우 인스턴스 필드 s 를 참조할 수 없으므로 static 필드 s 가 존재해야한다. 14에서도 프리뷰인 스펙이라 이 스펙이 끝까지 유지되지않을 수도 있다.


Helpful NullpointerExceptions

a.i = 99;

이런 코드에서 NPE 가 발생할 경우 아래와같은 에러메세지를 볼 수 있다.

Exception in thread "main" java.lang.NullPointerException
    at Prog.main(Prog.java:5)

에러메세지에는 파일명, 메서드, 문제의 코드라인을 보여주는데 위와같은 예제코드에서는 이 메세지로 어디가 문제인지를 찾을 수 있다. a 가 null 이라는것 말이다.

a.b.c.i = 99;
a[i][j][k] = 99;

하지만 이런 경우엔 문제의 라인을 안다고하더라도 어디가 null 인지 코드와 메세지만 보고서는 찾기가 어렵다(코드 자체도 썩 좋은코드로 보이지는 않지만).

a.i = b.j;
x().y().i = 99;

이런 경우에도 코드만 보고선 문제를 찾기 어렵다. "a가 null일까? b가 null일까?", "x()가 null일까 y()가 null일까?"

이런 에러메세지가 아래와 같이 좀 더 세분화되게된다.

Exception in thread "main" java.lang.NullPointerException: 
        Cannot assign field "i" because "a" is null
    at Prog.main(Prog.java:5)

Exception in thread "main" java.lang.NullPointerException: 
        Cannot read field "c" because "a.b" is null
    at Prog.main(Prog.java:5)

Exception in thread "main" java.lang.NullPointerException:
        Cannot load from object array because "a[i][j]" is null
    at Prog.main(Prog.java:5)

Exception in thread "main" java.lang.NullPointerException:
        Cannot read field "j" because "b" is null
    at Prog.main(Prog.java:5)



Records (Preview)

자바에 대해 불만을 얘기하는 사람들이 항상 주장하는 것들중 하나는 자바의 문법이 너무 장황하고 보일러플레이트 코드들이 많이 필요하다는 것이다. 자바보다 더 나은 경험을 제공하겠다며 나온 언어(대표적으로 코틀린)들이 가장 먼저 자바보다 낫다고 주장하는것들도 이부분이다. 객체가 아닌 단순 자료구조성 데이터 클래스도 자바에서는 별도의 문법이 없기때문에 클래스선언, 필드선언, 제어자(getter)를 정의해줘야하는것은 물론이고, toString(), hashcode(), equals() 와 같은 메서드들도 오버라이딩 해주어야한다. 그나마 롬복이라는 걸출한 라이브러리가 이를 해결해주고있긴하다.


이를 대체하기위해 record 라는걸 도입한다. record 는 코틀린의 data class 와 비슷하다는 생각이 들게되는데 위에서 얘기한 보일러플레이트를 상당히 줄여준다(하지만 이 기능의 목표가 자바 내 전반적인 보일러플레이트를 제거하는건 아니라고한다.).

record Person(String name, int age) {}

record 는 이런식으로 정의한다(kotlin 의 data class 와 유사하다.).

Person person1 = new Person("LichKing", 32);
System.out.println(person1);                
                                            
Person person2 = new Person("LichKing", 32);
System.out.println(person1.equals(person2));

클래스를 이용해 인스턴스를 생성하는 것과 마찬가지의 방법으로 사용할 수 있으며 toString() 이나 equals() 가 기본 오버라이딩 되어있다. 불변이고, 자료구조성 클래스이기때문에 인스턴스필드에 접근제어자를 붙일 수 없으며, 내부 데이터를 변경할 수 없다.

record Person(String name, int age) { 
    public boolean isMale() {         
        return true;                  
    }                                 
}                                     

이런 형태로 내부에 메서드를 정의할 수도 있다. 추가로 클래스를 상속받을 순 없으며 인터페이스 구현만 가능하다.


Switch Expressions (Standard)

기존 switch 문에서 다중 조건을 적용하기위해서는 아래와같이 해야했다.

switch (day) {
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        System.out.println(6);
        break;
    case TUESDAY:
        System.out.println(7);
        break;
    case THURSDAY:
    case SATURDAY:
        System.out.println(8);
        break;
    case WEDNESDAY:
        System.out.println(9);
        break;
}

하지만 이런코드는 기존 작성자가 이유가 있어서 break 를 뺀건지 실수로 누락한건지 의도를 알기 힘들었다(개인적으로 이런 switch 문을 매우 좋아하지않는다. 그래서 다중조건은 if 를 이용한다.).


그랬던 switch 문을 아래와같이 개선할 수 있게된다.

switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
    case TUESDAY                -> System.out.println(7);
    case THURSDAY, SATURDAY     -> System.out.println(8);
    case WEDNESDAY              -> System.out.println(9);
}

그리고 switch 문이 Statement 에서 Expression 으로 바뀐다. 그래서 이런식으로 리턴값을 받을 수도 있다.

public static void main(String[] args) {
    E e = E.A;                          
    int i = switch(e) {                 
        case A,B -> 1;                  
        case C -> 2;                    
    };                                  
                                        
    System.out.println(i);              
}                                       
                                        
enum E {                                
    A, B, C                             
}                                       

상당히 코틀린스러워졌다. 당연하게도 switch 내에서 System.out.println() 과 같이 void 메서드를 호출하면 리턴값이 없으므로 위 표현식은 사용할 수 없다. 그리고 모든 리턴값은 리턴값을 받는 타입에 의해 정의된다. 무슨말인가 하면 리턴값을 받는 변수의 타입이 Object 이면 switch expression 내에서 다양한 타입을 리턴해도 된다는 의미다.

public static void main(String[] args) { 
    E e = E.A;                           
    Object o = switch(e) {               
        case A,B -> 1;                   
        case C -> "1";                   
    };                                   
                                         
    System.out.println(o);               
}                                        
                                         
enum E {                                 
    A, B, C                              
}                                        

이런식으로 작성할 수 있다.


그런데 switch 에서 매칭됐을때 메서드를 하나 실행하고 값을 리턴하고싶은 경우도 있을 수 있다. 가령 이런 경우다.

int i = switch(e) {                       
    case B -> 1;                          
    default -> {                          
        // 출력문을 실행한 후 5를 리턴하고싶다.          
        System.out.println("hello");      
        5;                                
    }                                     
};                                        

당장 생각나는건 return 을 이용하는건데 switch 내에서 return 을 사용하면 switch 가 종료되는게 아니라 해당 메서드가 종료되어버린다. 이런 경우에 사용하기위해 yield 키워드가 추가됐다.

int i = switch(e) {                    
    case B -> 1;                       
    default -> {                       
        // 출력문을 실행한 후 5를 리턴하고싶다.       
        System.out.println("hello");   
        yield 5;                       
    }                                  
};                                     


Remove the Concurrent Mark Sweep (CMS)

CMS GC 가 삭제됐다. 이와함께 ZCG 의 윈도우, 맥 지원이 릴리즈노트에 포함된거보면 G1GC, ZGC 를 이용하라는 의미인것 같다.


Text Blocks (Second Preview)

멀티라인 문자열이 포함됐다. 많은 분들이 정식 릴리즈하기를 기다리고있는 내용이지 않을까 싶다.

String sql = """                  
            SELECT * FROM DUAL;   
        """;                      
                                  
System.out.println(sql);          

이런게 가능해진다.


참고: https://openjdk.java.net/projects/jdk/14/

18
4
  • 댓글 12

  • zepinos
    19k
    2020-02-07 17:46:13 작성 2020-02-07 17:49:23 수정됨

    좋은글 고맙습니다. 이번 버젼이 LTS 인가요?


    이런...확인해보니 17 이 다음 LTS 군요...

    0
  • LichKing
    15k
    2020-02-07 17:52:23

    위키피디아에서 가져온 표인데 11다음 LTS는 17인가봅니다. 까마득하네요



    0
  •  (づ。◕ ܫ ◕。)づ
    4k
    2020-02-07 20:05:28

    아직 8도 제대로 모르는데 눈물....😥

    1
  • ljseokd
    241
    2020-02-08 09:48:39

    좋은 글 감사합니다.


    0
  • 답정너심판자
    1k
    2020-02-08 18:04:47

    코틀린 처럼 되는거 같네요 ㅡㅡㅋㅋ

    0
  • onimusha
    7k
    2020-02-10 09:14:36

    NPE 지옥에 대한 입문자들의 좌절감이 많이 덜어질 수 있을 것 같네요..

    0
  • John Suhr
    1k
    2020-02-10 12:15:52
    정보글 감사드립니다. 종국에는 코틀린이랑 하나가 되는건 아닐런지...
    0
  • B급 개발자
    464
    2020-02-10 16:31:39 작성 2020-02-10 16:31:57 수정됨

    1.4로 잘못 봤네요. 아재 인증인가요?

    좋은 글 감사드립니다.

    0
  • 거신
    383
    2020-02-10 21:00:56
    끝부분은 진짜 그냥 코틀린이 되었네요 ㅎㅎ 멀티라인 스트링은 진짜 최고 ㅎㅎ
    0
  • 아야로
    1k
    2020-02-11 08:55:56
    강화된 예외 로그, 개선된 스위치 문, 멀티라인 텍스트까지 완전 대박이네요.
    이 정도로 발전하는 언어라니... 다음LTS 나올날이 정말 기대됩니다.
    0
  • 하마
    6k
    2020-02-13 08:37:00 작성 2020-02-13 11:45:18 수정됨

    드디어 멀티라인 스트링. ㅎㅎ

    현재 엔터프라이즈향 블록체인의 대표플랫푬 4개중 2개가 자바로 짜여 있습니다.
    R3 Corda와 Hyperleder besu가 주인공이죠. (나머지 둘은 Golang) 

    누가 뭐라해도 대중성,기업형에서는 자바가 으뜸이라는게 세계공통이라는 것인데,
    이렇게 꾸준히 변화해 간다면 그 위치 오래오래 갈 듯 합니다. 


    0
  • 듬뿍
    41
    2020-02-13 09:38:54

    멀티라인 스트링이 드디어 되는군요.

    0
  • 로그인을 하시면 댓글을 등록할 수 있습니다.