자바 17

  • 자바 11 릴리즈 이후 자바 17싸지 추가된 자바 작성에 대한 새로운 기능
    • Text 블록
    • switch 표현식
    • record
    • sealed 타입

Text 블록

  • 자바는 큰따음표로 감싼 문자열만 제공했음
  • 긴문자열 사용이 불편했고 특정 문자 사용시 이스케이프가 필요
  • 예시 - json 표현시
    • to-be
// language=json
String json = "{\"key\":\"value\"}";
  • as-is
// language=json
String json = """
    {
        "key1": "value",
        "key2": "value",
        "key3": "value"
    }
""";
  • 특징
    • “““text”””
    • 각 줄은 공백으로 들여쓰기 가능, 공백은 무시됨
    • 가장 잛은 들여쓰기가 기준점이됨
    • 클래스 파일에 상수를 기록하기전 javac가 Text블록을 처리
    • 종결문자 LF로 처리
    • 이스케이프 시퀀스를 마지막에 해석
  • 아직까지는 보간법을 지원하지 않음
    • kotlin 예시
val nameForPrint: String = "[${codeItem.code}] ${codeItem.name}"

21에 preview feature로 존재

https://openjdk.org/jeps/430

switch 표현식

  • 기존
    • break가 없으면 다음 case가 수행됨
    • 표현식(expression) 불가
      • 리턴 불가
  • 예시
String message = switch (month) {
    case 1, 2, 12 -> "Winter, brrrr";
    case 3, 4, 5 -> "Spring has sprung!";
    case 6, 7, 8 -> "Summer is here!";
    case 9, 10, 11 -> "Fall has descended";
    default -> {
        throw new IllegalArgumentException("Oops, that's not a month");
    }
};
  • 표현식으로 처리 가능
  • 쉼표로 여러개 처리 가능
  • default가 없는경우 컴파일 에러
    • enum 인경우 모든 상수가 명시되어있으면 default 구문 생략가능
  • 이후 살펴볼 패턴 매칭으 위한 디딤돌이기도함

record

  • 다음을 위한 새로운 형태의 자바 클래스 (아래의 순서가 중요 - 상용구 감소, 문법보다 언어 의미론에 더 중점을 둠)
    • 데이터 전용 집계 모델링을 위한 최고 수준의 수단 제공
    • 자바의 타입 시스템에서 발생할 수 있는 격차 해소
    • 공통 프로그래밍 패턴을 위한 언어 수준 문법 제공
    • 클래스 상용구 감소
  • record의 아이디어는 자바 언어를 확장해서 클래스를 ‘필드, 오직 필드만’으로 명시하는 방법을 만드는것
  • 클래스를 유용하기 위해 너무 많은 메서드들을 정의해야함, 지루하고 반복적, 기계적으로 생성가능(이펙티브 자바 참고)
    • toString
    • hashCode, equals
    • getter 메서드들
    • 공개 생성자
  • 코드가 변경될때마다 위 메서드들을 확인하고 수정하는 작업이 필요
  • record는 이러한 문제를 해결
    • 컴파일과 런타임에 동작
  • FXOrderClassic 예시 클래스
    • FX 통화 거래의 기본 주문 유형을 표현
    • 주문을 표현하는 필드 외 부가적인 코드들이 많음
      • 생성자
      • getter
      • equals
      • hashCode
      • toString
  • 특징
    • 모든 멤버는 final
    • 동일한 이름의 접근자
    • 표준 생성자(canonical constructor)
    • toString, equals, hashCode는 invokedynamic 기반의 메커니즘에 의해 구현됨
    • 최상위 클래스는 java.lang.Record
    • final 클래스
  • record 기능의 디자인적 측면
    • 자바의 열거형은 디자인 패턴(유한한 수의 타입세이프 인스턴스로 관리됨)을 구현한 구문 오버헤드를 최소화한 형태
    • 레코드 또한 최소한의 구문으로 패턴(데이터 캐리어, 일면 just holds fields)을 구현한 특수한 형태
  • 초기 디자인
    • POJO의 상용구 감소
    • 자바 빈 2.0
    • 네임드 튜플
    • 곱 타입
  • 추가 질문들
    • 하이버네이트에서 프록시 가능여부
    • 전통적인 자바빈과의 호환여부
    • 이름제거와 형식 유연성 지원여부
    • 패턴 매칭과 구조 분해 지원여부
  • 최종적 디자인 결정은 네임드 튜플

명목적 타이핑

  • 자바는 명목적 타이핑(nominal typing) 기반 언어
    • 타입의 이름으로 객체의 타입결정객체의 타입결정
  • 구조적 타이핑 (structural typing)
    • 객체의 필드와 메서드에 따라 타입결정
  • record는 명목적 타이핑에 기반하여 도입
    • 복합키(맵), 다중반환
  • 메서드, 생성자, 정적 필드를 정의가능
    • 이러한 선택은 신중해야함
    • 레코드의 설계 의도는 관련된 필드를 하나의 불변속성의 데이터로 그룹화하는것

콤팩트 레코드 생성자

  • 콤팩트 레코드 생성자를 사용하면 커스텀 생성자를 정의하면서도 불필요한 코드를 줄일수 있음
    • 책 예시 참고
      • 유효성 검사
      • 정적 팩토리 메서드
      • 대체 생성자
      • record 기반 map key

레코드 결론

  • 튜플 버전인 단순한 캐리어로 설계됨
  • 클래스를 더 명확하고 작게 만들수 있음
  • 많은 수작업 코딩 생략 가능
  • lombok과 같은 별도 라이브러리 사용을 줄이거나 제거 가능

sealed 타입

  • 열거형은 해당 유형이 가질 수 있는 모든 값을 타입세이프하도록 처리가능
  • 디컴파일시
    • 클래스 파일 내에서 열거형 값들은 public static final로 처리
    • 싱글톤과 비슷하지만 하나가 아닌 유한한 개수가 있음
    • 열거형 타입의 객체가 주어졌을때 완전성(exhaustiveness)을 제공
      • 객체가 표현가능한 모든값을 알 수 있음
  • 자바 11에서 다양한 주문을 모델링 하고 싶은경우
    • 모든 필드가 포함된 여러개의 주문
      • 개발자가 일일이 어떤 타입의 주문이 있는지 확인필요
    • 추상 클래스를 만들고 이를 서브 클래싱해서 구체적인 타입들 정의
      • 원하지 않는 확장 발생가능
  • 문제는 자바는 항상 기본적으로 확장 가능한(open inheritance) 언어로 설계 된 것
  • sealed는 이러한 문제를 해결
    • 알려진 하위 타입들에 의해서만 확장가능
  • 책 예시
    • 현재 컴파일 유닛 내에서만 확장 가능
      • 내부 클래스가 상속
      • abstract를 사용해서 앞서 설명한 객체지향 모델링 패턴을 깔끔한 방식으로 구현
  • 인터페이스에서도 사용가능
    • 클래스 보다 인터페이스에서 사용될 가능성이 더 높음
    • 책 예시
      • permits 키워드
        • sealed 인터페이스를 구현할수 있는 클래스를 나열
      • record가 구현
      • 이제 상위 인터페이스만으로 실제 구현체를 알 수 있음
        • 라이브러리 코드는 두 경우만 있다고 안전하게 가정 가능
        • 사용하는 클라이언트도 불필요한 위반불가능
  • 자바 객체 지향의 두 가지 모델간 관계에 한 가지가 추가됨
    • is-a
    • has-a
    • is-either-a (sealed)
  • 또 다른 관점
    • 최종(final)과 공개(open) 사이의 중간 지점
    • 타입에 적용된 열거형 패턴
  • 여러 언어의 타입에 대한 이론적인 측면 소개
  • 마지막으로 짚고 넘어가야하는것은 허용하는 모든 타입은 확장하는 베이스 클래스가 있다는것
    • String, Integer는 Object를 제외하고는 공통 상속 관계가 없음
      • String 또는 Integer 표현 불가능

instanceof의 새로운 형식

  • x instanceof Y
    • Y 유형의 변수에 x를 할당할 수 있으면 true, 아니면 false
  • 악평을 받고 있는데, 객체의 타입과 매개변수의 타입 선택에서 정확성이 부족하다는 것을 의미
    • 객체지향 훼손
  • 컴파일 시점에 완전히 알 수 없는 유형들을 직면하는 경우도 있음, 이러한 상황에서는 사용
    • ClassCastException 예방
  • 자바 17에서는 instanceof 연산자가 타입이나 타입 패턴을 받도록 확장됨
    • 타입 패턴은 타입을 지정하는 술어와 단일 패턴 변수로 구성됨
    • 책 예시
      • 분기내 포함, 별도 캐스팅 불필요
  • JEP 394: instanceof에 대한 패턴 매칭
  • 패턴이란 두 가지의 조합?
    • 값에 적용될 술어
    • 값에서 추출할 로컬 변수 집합
    • 핵심은 술어가 값에 적용된 경우에만 패턴 변수가 추출된다는것
  • 자바 17에서는 instanceof 연산자가 타입이나 타입 패턴을 받도록 확장된것

패턴 매칭과 프리뷰 기능

  • 언어의 새로운 기능은 모두 동일한 생명 주기를 거침
    • 프리뷰 → 공개 프리뷰 → 최종 기능으로 제공됨
  • 여기서는 instanceof에서 switch로 패턴 매칭을 확장하는 프리뷰 기능을 살펴봄
  • 알 수 없는 타입의 객체를 처리해야하는 경우 패턴 매칭
  • 이렇게 작성하면 코드가 불편하고 장황해짐
  • switch로 처리하면?
  • 자바 17의 패턴 매칭 프리뷰 버전에서는 Sealed 타입과 긴밀하게 통합 할 수 있는 기능 존재
  • 주의할 점
    • case null을 포함, null-safe하고 NPE 발생을 예방
    • default가 필요없음
    • 컴파일러가 FX.. 모든 하위 타입 검사가능
    • 누락된 케이스가 존재하는 경우에만 default를 사용하면됨

요약

  • 여러 줄 문자열을 위한 Text 블록
  • switch 표현식
  • records
  • seald 타입
  • 패턴 매칭