JDK11은 JDK1.8 이후 등장한 첫 LTS(Long Term Support)버전이다.
프로그래밍적인 요소는 아니지만 11로 오면서 가장 큰 변화는 Oracle JDK를 상업용으로 사용할 때에는 라이센스가 필요하며 대신 OpenJDK(https://openjdk.org/projects/jdk/), Zulu(https://www.azul.com/downloads/#zulu) 등을 사용해야 한다.
기능상 차이점은 없기 때문에 그냥 무료의 JDK들을 설치해서 사용하면 된다.
개발적인 측면의 신 기능들
String 클래스에 새로운 메서드들 추가
- isBlank: 문자열이 의미있는 내용으로 채워져있는지 검사하기 위해서 기존에는 isEmpty를 사용할 수 있었는데 이 녀석은 그냥 문자열의 길이가 0인지만 보는 녀석이었다. 반면 isBlank는 white space를 제외하고 판단한다.
@Test
public void stringMethodTest(){
String hello = " ";
Assertions.assertFalse(hello.isEmpty());
Assertions.assertTrue(hello.isBlank());
}
- lines: 여러 줄로 입력된 문자열을 구분자로 분리한 Stream을 반환하는 메서드이다. 이때 구분자는 \r, \n, \r\n 이 사용될 수 있다.
- strip, stripLeading, stripTrailing: 기존의 trim 메서드가 세분화 되었다. trim은 시작과 끝에서의 공백을 모두 제거했다면 이 기능은 strip이 물려 받고 앞에서(stripLeading), 뒤에서(stripTrailing) 공백을 제거할 수 있게 되었다.
@Test
public void linesStripTest(){
String multiStr = "Hello \r\n Happy \r \n Java\nWorld";
multiStr.lines().filter(line -> !line.isBlank())
.forEach(line -> System.out.println(line+" : "+line.length()));
List<String> list =multiStr.lines().filter(line -> !line.isBlank())
.map(String::strip)
.collect(Collectors.toUnmodifiableList());
Assertions.assertEquals(list, List.of("Hello", "Happy", "Java", "World"));
}
- repeat: 문자열을 주어진 count만큼 반복해서 새로운 문자열을 만들어준다.
@Test
public void repeatTest(){
String sample = "Hi";
String repeated = sample.repeat(4);
Assertions.assertEquals(repeated, sample+sample+sample+sample);
}
Files를 이용한 문자열 직접 파일에 쓰기 및 읽기
기존에는 문자열을 파일에 저장하거나 파일에서 읽어오기 위해서 Stream을 연결해야했지만 Files에서 제공하는 readString, writeString을 이용하면 Stream없이 쉽게 처리할 수 있게 되었다.
@Test
public void filesTest() throws IOException {
String content = "Sample text";
Path target = Path.of("c:/Temp/test.txt");
// 파일에 쓰기
Path filePath = Files.writeString(target, content);
// 파일에서 읽어오기
String fileContent = Files.readString(filePath);
assertEquals(fileContent, content);
}
Collection 내용을 배열로 만들기
Collection을 이용해서 배열을 생성할 때 toArray 함수를 사용하는데 이때 lambda 식을 이용할 수 있게 되었다.
@Test
void test() {
List<String> list = Arrays.asList("1","2","3");
// String [] arr = list.toArray(new String[list.size()]); // 기존
String [] arr = list.toArray(String[]::new); // JDK 11
}
Predicate에 static boolean not 메서드 추가
Predicate에 static한 not 메서드가 추가되었다. 특히 Stream을 구성하는 요소가 자체로 boolean을 반환할 때 유용할 듯 하다.
@Test
public void testPredicate(){
String [] data = {"Hello", "", "\n", "Java", "World"};
long cnt = Arrays.stream(data).filter(Predicate.not(String::isBlank )).count();
assertEquals(cnt, 3);
}
lambda 식에서 local-variable 문법
이제 lambda 식에 사용된 변수의 타입 var 변수에 타입 annotation을 선언할 수 있게 되었다.
@Test
public void localVarTest() {
String[] strs = {"Hello", "Java", "World"};
String resultString = Arrays.stream(strs)
.map(x -> x.toUpperCase()) // x에 대한 한정 불가
.collect(Collectors.joining(", "));
assertEquals(resultString, "HELLO, JAVA, WORLD");
resultString = Arrays.stream(strs)
.map((@Deprecated var x) -> x.toUpperCase())
.collect(Collectors.joining(", "));
assertEquals(resultString, "HELLO, JAVA, WORLD");
}
JDK 10에 추가된 var 키워드를 보고 뭐에 쓰는 녀석일까 궁금했는데 상당히 유의미한 용법이 생긴듯 하다. lambda 식을 사용할 때 타입이 유동적인 경우 파라미터의 타입을 생략할 수 있는데 이 경우는 그 타입에 대한 annotation 추가가 불가하다.
이제 var 키워드를 이용할 수 있기 때문에 이 변수에 타입 annotation 사용이 가능해졌다. 사실 @Deprecated를 쓸일은 없겠지만 @Nullable 등은 유용할 듯 싶다.