포스트

2023-04-27-TIL

2023-04-27-TIL

Today I Learned

Sealed Class in Java

Java 15에서 sealed 클래스의 개념을 소개하였다. Java sealed 클래스 및 인터페이스는 해당 클래스와 인터페이스로부터 extend 또는 implement 하는 것을 제한한다.

다시 말해, sealed 클래스나 인터페이스는 아무나 상속하거나 구현할 수 없고, 직접 허용한 클래스만 하위 타입이 될 수 있다. 이는 클래스나 인터페이스로 하여금 서브타입을 좀 더 제어할 수 있게 해준다.

정확한 이력은 JEP 409에 나와 있다. sealed 클래스는 JEP 360으로 JDK 15에 프리뷰 기능으로 처음 들어왔고, JEP 397로 JDK 16에서 한 번 더 프리뷰를 거친 뒤, JDK 17에서 정식 기능이 됐다(JEP 409: Sealed Classes). 그러니 프리뷰 옵션 없이 쓰려면 Java 17 이상이 필요하다.

허용할 하위 클래스는 permits 절로 적는다. 그리고 허용된 하위 클래스는 반드시 final, sealed, non-sealed 중 하나를 선언해서, 계층을 거기서 닫을지, 다시 제한할지, 열어 둘지를 밝혀야 한다.

1
2
3
4
5
sealed interface Shape permits Circle, Square, Rectangle {}

final class Circle implements Shape { double radius; }
final class Square implements Shape { double side; }
non-sealed class Rectangle implements Shape { double w, h; }

왜 필요한가. 일반 인터페이스는 누구나 구현할 수 있어서, Shape를 받는 코드가 가능한 모든 경우를 알 수 없다. sealed로 하위 타입을 닫아 두면 “도형은 이 세 가지뿐”이라는 도메인 지식이 타입에 드러난다. 반대로 final은 상속을 아예 막아서 “정해진 몇 가지 중 하나”라는 계층 자체를 만들 수 없다. sealed는 완전히 열린 상속과 완전히 닫힌 final 사이의 선택지다.

Kotlin에도 같은 개념이 있다. Kotlin 문서는 sealed 클래스의 모든 직접 하위 클래스가 컴파일 시점에 알려져 있다고 설명하고, 하위 클래스는 같은 모듈과 같은 패키지 안에 있어야 한다. 덕분에 when 식에서 모든 하위 타입을 다루면 else 분기가 필요 없다(Kotlin: Sealed classes and interfaces).

1
2
3
4
5
6
7
8
sealed interface Result
data class Success(val data: String) : Result
data class Failure(val error: Throwable) : Result

fun render(r: Result) = when (r) {
    is Success -> r.data
    is Failure -> "error: ${r.error.message}"
}
  • https://www.javatpoint.com/sealed-class-in-java#:~:text=Java%20sealed%20classes%20and%20interfaces,control%20over%20their%20permitted%20subtypes.
  • https://velog.io/@ho-taek/Kotlin-Sealed-Class%EB%9E%80#:~:text=Sealed%20Class%EC%9D%B4%EB%8B%A4.-,1.%20Sealed%20Class%EB%9E%80,%EB%82%98%ED%83%80%EB%82%B4%EB%8A%94%EB%8D%B0%20%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94%20%ED%81%B4%EB%9E%98%EC%8A%A4%EC%9D%B4%EB%8B%A4.
참고한 자료외부 출처 2

외부 출처

이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다