-
자바 JDK 9 부터 JDK17까지의 주요 코딩 특징스터디 노트 2023. 10. 12. 20:57
아래 자료들은 최범균님의 영상을 보고 제작하였습니다.
원본 강의 영상 : https://youtu.be/7SlDdzVk6GE?si=adWuAndOQHY-40Pk
JDK 9
📌 JDK8에서 인터페이스에 default 메서드와 static 메서드를 선언할 수 있게 되었는데, 9에서는 private 메서드도 추가할 수 있게 되었음.
public interface Client { void exchange(); default void get() { logging2("before"); exchange(); logging("call get"); } private void logging(String msg) { System.out.println(msg); } private void logging2(String msg) { System.out.println(msg); } }
📌 try-with-resource 문법을 사용할 수 있음.
// JDK 9 이전 // try 구문에 변수를 넣어주면 에러가 나며 구문 안에서 선언해주어야 함. BufferedReader br = Files.newBufferedReader(Paths.get("a.txt")); try (br) { // Error ❌ String line = br.readLine(); ... } catch (IOException e) { e.printStackTrace(); } // JDK 9 // 괄호 안에 실질적인 final 변수면 넣어줄 수 있게 되었음. BufferedReader br = Files.newBufferedReader(Paths.get("a.txt")); try (br) { // Non error ⭕ String line = br.readLine(); ... } catch (IOException e) { e.printStackTrace(); }
📌 Collection Factory Method
List<Integer> list = List.of(1, 2, 3); Map<String, Integer> map = Map.of("a", 1, "b", 2); Set<Integer> set = Set.of(1, 2, 3);
콜렉션 구현체에 of()라는 팩토리 메소드가 생겼음.
이전까지는 Arrays.asList(...)를 통해 만들었어야 했음.
📌 Arrays(compare, mismath)
int comp = Arrays.compare(a, b); // 두 배열을 비교하는 것 int firstIdx = Arrays.mismatch(a, b); // 두 배열이 어디에서 다른지 비교
JDK 10
📌 Var
var a = 10; // a는 int 타입 var result = new ArrayList<Integer>();
로컬 변수 타입 추론 기능이 추가됨.
11에서는 람다식에서도 사용이 가능해짐.
JDK 11
📌 String 클래스 유용한 메소드들 추가
- isBlank() : 공백문자만 포함했는지 여부
ex) Character.isWhitespace(int);
- lines() : 라인이 스트림으로 제공이 됨
ex) Stream<String> lines = name.lines();
- repeat() : 문자열의 반복
ex) String str = "1".repeat(10);
- strip(), stripLeading(), stripTrailing() : 공백문자에 해당하는 앞 뒤 문자를 제거함.
ex) Character.isWhitespace(int);
📌 Files
Files클래스에 문자열을 통으로 저장하고 읽어올 수 있는 메소드가 추가되었음.
- Files.writeString()
- Files.readString()
Files.writeString(Path.of("a.txt"), "string", StandardOpenOption.CREATE); String str = Files.readString(Path.of("a.txt"));
기본 인코딩은 UTF-8
JDK 12
📌 String 클래스에 메소드 추가
- indent(int n) : n 만큼 들여쓰기 또는 내어쓰기
- <R> R transform(Function<? super String, ? extends R> f) : 문자열을 다른 타입으로 바꿀 때 사용
JDK 14
📌 Switch 식
String grade = switch (mark) { case 10 -> "A"; case 9 -> "B"; case 8 -> "C"; case 7 -> "D"; default -> "F"; };
switch문을 통해 값을 만들어낼 수 있으며 변수에 할당할 수 있고 return도 바로 가능함.
대신 case -> 형식으로 문법이 바뀌었으며 무조건 값을 만들어야함.
JDK 15
📌 Text block
String json = """ { "name" : "json", "pubdate" : "2023-10-12" }""";
여러 줄에 걸쳐서 문자열을 입력이 가능해졌음.
📌 String.formatted()
String old = String.format("name: %s", "java"); // 15 이전 String v15 = "name: %s".formatted("java"); // 15 이후
📌 NPE 메시지 개선
System.out.println(name.getFirst().toUpperCase());
위에서 NPE 발생 시 다음과 같이 친절하게 오류 설명을 해줌.
java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because the return value of "ver15.Name.getFirst()" is null
JDK 16
📌 Stream.toList() & Stream.mapMulti()
// toList() List<Integer> nos1 = Stream.of(1, 2, 3).filter(n -> n % 2 == 0).toList(); // jdk 16 List<Integer> nos2 = Stream.of(1, 2, 3).filter(n -> n % 2 == 0).collect(Collectors.toList()); // 이전 버전 // mapMulti() List<Integer> result = Stream.of(1, 2, 3) .mapMulti((Integer no, Consumer<Integer> consumer) -> { consumer.accept(no); consumer.accpet(-no); }).toList();
📌 instanceof와 패턴 매칭
if (a instanceof String s) { // s : 패턴 변수 System.out.println(s); } if (a instanceof String t && t.isBlank()) { System.out.println("blank"); } if (!(a instanceof String b)) { return; } System.out.println(b.toUpperCase());
맨 위의 코드를 보면 만약 a가 String이면 s라는 변수가 만들어저 if 블록 내에서 s를 활용할 수 있게 된다.
또한 t를 바로 활용하여 t.isBlank()로 바로 활용할 수 있다.
세번째는 return을 바로 하면(early return) b를 그 다음에서 바로 활용할 수 있다.
📌 Record Class
record FullName(String first, String last) { public String formatter() { return first + " " + last; } } FullName fn = new FullName("f", "l"); fn.first(); fn.last();
Recod Class 내의 first, last 필드에 대해
- private final 필드로 선언
- 파라미터를 기본으로 가진 생성자가 선언됨
- 같은 이름의 메서드가 만들어짐(getter)
- hashCode, equals, toString이 기본으로 만들어짐
특징
- 기본 생성자 없음(무조건 값을 받아야 함)
- 값 변경 메서드 없음(필드가 final이기 때문에)
- final 클래스(추상클래스 아님)
- 다른 클래스 상속 불가
JDK 17
원본 강의 영상 : https://youtu.be/GJB-RyHKHjY?si=k0VF9Ias7QtRKgVZ
📌 sealed class & interface
public sealed interace FList<T> permits Cons, Empty { // } public final class Cons<T> implements FList<T> { private T head; private FList<T> tail; public Cons(T head, FList<T> tail) { this.head = head; this.tail = tail; } ... } public final class Empty implements FList<T> { // }
sealed는 상속할 수 있는 타입을 제한할 수 있는 기능을 제공한다.
class나 interface 앞에 선언해서 사용할 수 있다.
permits은 extends 뒤에 붙게 된다. 허용하는 하위 타입 목록을 지정할 수 있게되고 하위 타입이 존재해야만 한다.
즉, sealed와 permits는 한몸으로 사용한다.
그리고 sealed 타입을 상속한 타입은 제약이 있다.
- 클래스에 final를 붙여서 상속 불가 상태로 만든다.
- sealed(+permits)를 붙여서 다시 상속 가능한 상태로 만든다.
- non-sealed를 붙여서 제한하지 않음을 선언해야 한다.
또한 sealed 타입과 같은 패키지에 위치해야하거나 같은 모듈 내에 위치해야 한다.
단, 같은 java 파일 내에 하위 타입이 위치하면 permits를 생략할 수 있다.
// Cons Class public final class Cons<T> implements FList<T> { private T head; private FList<T> tail; public Cons(T head, FList<T> tail) { this.head = head; this.tail = tail; } ... } // 하위 클래스 final class SomeCons<T> extends Cons<T> { public SomeCons(T head, FList<T> tail) { super(head, tail); } }
record 클래스 또한 sealed interface를 상속받아 사용할 수 있다.
public sealed interface FList<T> permits Cons, Empty { // ... } public record Cons<T>(T head, FList<T> tail) implements FList<T> { // ... }
📌 switch에서 패턴 매칭
// jdk 17 return switch(flist) { case Cons c -> 1 + c.getTail().size(); default -> 0; } // jdk 16 if (a instanceof String t && t.isBlank()) { System.out.println("black"); }
'스터디 노트' 카테고리의 다른 글
Java Optional의 메소드 사용 설명서(Optional 잘 활용하기) (1) 2023.10.16 [Java] IntStream 메소드 사용해보기 (0) 2023.10.16 [Java] 객체 필드 Validation 손쉽게 구현하기 (feat. Bean Validation & @NotNull) (0) 2023.10.12 자바 21 특징 - SequencedCollection (2) 2023.10.10 자바 21 특징 - 가상 쓰레드 (1) 2023.10.09