티스토리 뷰
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);
이런게 가능해진다.
'Java' 카테고리의 다른 글
동기화 방법에 따른 데드락 상태에서 스레드 덤프 차이 (0) | 2020.03.29 |
---|---|
동기화 클래스 사용하기(CountDownLatch, Semaphore, CyclicBarrier) (0) | 2020.03.05 |
DesignPattern#04. Singleton Pattern (0) | 2019.10.19 |
DesignPattern#03. Decorator Pattern (1) | 2019.10.08 |
'generic array creation' compile error (0) | 2019.09.27 |
- Total
- Today
- Yesterday
- OOP
- spring cloud
- MySQL
- EffectiveJava
- http
- 정규표현식
- TEST
- clean code
- javascript
- java
- JPA
- toby
- code
- frontcode
- Design Pattern
- Jackson
- servlet
- JavaScript Core
- frontend개발환경
- db
- Spring
- generics
- backend개발환경
- Git
- java8
- Kotlin
- mariadb
- programming
- go-core
- DesignPattern
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |