Java 12의 새로운 기능
1. 새로운 기능들
1.1 String class의 새로운 메서드
Java 12는 String class에서 2가지 새로운 메서드를 제공한다.
1) indent
정수 파라미터를 바탕으로 각 라인의 들여쓰기를 조정하는 메서드이다. 만약 파라미터 값이 0보다 크면, 새로운 space가 각 라인 앞에 삽입된다. 반면 파라미터 값이 0보다 작으면, 각각의 라인 앞의 space를 제거한다. 만약 주어진 라인이 충분한 white space를 가지고 있지 않다면, 모든 white space가 제거된다.
간단한 예시를 살펴보자. 먼저 4 space로 들여쓰기를 추가하고, 모든 들여쓰기를 제거할 것이다.
String text = "Hello Baeldung!\nThis is Java 12 article.";
text = text.indent(4);
System.out.println(text);
text = text.indent(-10);
System.out.println(text);
출력 값은 다음과 같다.
Hello Baeldung!
This is Java 12 article.
Hello Baeldung!
This is Java 12 article.
들여쓰기 값을 초과하는 -10이라는 값을 넘겼음에도 불구하고, 문자는 영향을 받지 않고 오직 space만 제거되었다.
2) transform
이 메서드는 단일 인자 function을 파라미터로 받는다. 이 function은 string에 적용된다.
문자열의 앞뒤를 뒤바꾸는 다음 예시를 살펴보자.
@Test
public void givenString_thenRevertValue() {
String text = "Baeldung";
String transformed = text.transform(value ->
new StringBuilder(value).reverse().toString()
);
assertEquals("gnudleaB", transformed);
}
1.2 File의 mismatch 메서드
public static long mismatch(Path path, Path path2) throws IOException
이 메서드는 두 파일을 비교하고 그들의 내용 중 처음으로 mismatch되는 곳의 위치를 반환한다.
반환 값은 0부터 더 작은 파일의 byte 사이즈가 될 것이며, 두 파일이 동일할 경우 -1을 반환한다.
동일한 2개의 파일을 비교해서 반환 값이 -1이 되는 다음 예시를 살펴보자.
@Test
public void givenIdenticalFiles_thenShouldNotFindMismatch() {
Path filePath1 = Files.createTempFile("file1", ".txt");
Path filePath2 = Files.createTempFile("file2", ".txt");
Files.writeString(filePath1, "Java 12 Article");
Files.writeString(filePath2, "Java 12 Article");
long mismatch = Files.mismatch(filePath1, filePath2);
assertEquals(-1, mismatch);
}
2번째 예시는 두 파일이 다른 내용을 가지고 mismatch되는 위치가 8을 리턴한다.
@Test
public void givenDifferentFiles_thenShouldFindMismatch() {
Path filePath3 = Files.createTempFile("file3", ".txt");
Path filePath4 = Files.createTempFile("file4", ".txt");
Files.writeString(filePath3, "Java 12 Article");
Files.writeString(filePath4, "Java 12 Tutorial");
long mismatch = Files.mismatch(filePath3, filePath4);
assertEquals(8, mismatch);
}
1.3 Teeing Collector
Java 12에서는 Collectors class에 teeing collector가 추가되었다.
Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1,
Collector<? super T, ?, R2> downstream2, BiFunction<? super R1, ? super R2, R> merger)
이것은 두 downstream collector의 합성물이다. 모든 요소들은 2개의 downstream collector에 의해 처리된다. 그런 다음 그들의 결과값은 merge function으로 넘어가서 최종 결과물로 변환된다.
다음은 숫자들의 평균값을 계산하는 teeing collector의 사용 예시이다. 첫번째 collector는 파라미터들의 값을 모두 더한다. 그리고 두번째 collector는 파라미터들의 갯수를 제공한다. 마지막으로 merge function은 이 두 값을 이용하여 평균값을 계산한다.
@Test
public void givenSetOfNumbers_thenCalculateAverage() {
double mean = Stream.of(1, 2, 3, 4, 5)
.collect(Collectors.teeing(Collectors.summingDouble(i -> i),
Collectors.counting(), (sum, count) -> sum / count));
assertEquals(3.0, mean);
}
1.4 Compact Number Formatting
Java 12는 CompactNumberFormat이라는 새로운 Number format을 제공한다. 이것은 숫자들을 더 짧은 형태로 나타내기 위해 디자인되었다. 이 패턴들은 주어진 locale을 기반으로 제공된다.
우리는 NumberFormat class의 getCompactNumberInstance 메서드를 통해 객체를 얻을 수 있다.
public static NumberFormat getCompactNumberInstance(Locale locale, NumberFormat.Style formatStyle)
이전에 언급했던 것 처럼, locale 파라미터에 따라 적절한 format 패턴이 결정된다. format 스타일은 SHORT, LONG으로 정해질 수 있다. 예를 들어 1000이라는 숫자를 US locale로 생각해보자. SHORT 스타일은 '10K'가 될 것이고, LONG 스타일은 '10 thousand'가 될 것이다.
@Test
public void givenNumber_thenCompactValues() {
NumberFormat likesShort =
NumberFormat.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.SHORT);
likesShort.setMaximumFractionDigits(2);
assertEquals("2.59K", likesShort.format(2592));
NumberFormat likesLong =
NumberFormat.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.LONG);
likesLong.setMaximumFractionDigits(2);
assertEquals("2.59 thousand", likesLong.format(2592));
}
2. Preview Changes
새로운 기능들 중 일부는 오직 Preview로만 제공된다. 이것들을 활성화하기 위해서, 우리는 IDE 상의 적절한 세팅 값을 바꾸거나 컴파일러에 옵션값을 다음과 같이 줘야한다.
javac -Xlint:preview --enable-preview -source 12 src/main/java/File.java
2.1 Switch 표현식 (Preview)
이전 구문과 새로운 구문을 비교해보자. 먼저 이전 구문이다.
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
String typeOfDay = "";
switch (dayOfWeek) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
case FRIDAY:
typeOfDay = "Working Day";
break;
case SATURDAY:
case SUNDAY:
typeOfDay = "Day Off";
}
이번에는 새로운 구문이다.
typeOfDay = switch (dayOfWeek) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Working Day";
case SATURDAY, SUNDAY -> "Day Off";
};
새로운 switch 구문이 더 compact하고 가독성이 좋다. 또 다른 차이점은 switch 구문을 통해 변수에 직접적으로 값을 할당하는 것이 가능해졌다는 것이다. 물론 반환 값이 없는 switch 구문도 가능하다.
switch (dayOfWeek) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> System.out.println("Working Day");
case SATURDAY, SUNDAY -> System.out.println("Day Off");
}
복잡한 로직을 작성하기 위해서는 중괄호를 활용하면 된다.
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> {
// more logic
System.out.println("Working Day")
}
2.2 instanceof의 패턴 매칭 (Preview)
이전 자바 버전에서는 instanceof를 통해 클래스가 확인되었다고 하더라도, 명시적으로 타입 캐스팅을 아래와 같이 해줘야 했다.
Object obj = "Hello World!";
if (obj instanceof String) {
String s = (String) obj;
int length = s.length();
}
자바 12에서는 새로운 타입 캐스팅이 된 변수를 아래와 같이 다이렉트로 선언할 수 있다.
if (obj instanceof String s) {
int length = s.length();
}
※ 참조