pattern matching 은 객체가 특정 구조를 가지고 있는지 테스트한 다음 일치하는 경우 해당 객체에서 데이터를 추출하는 작업을 포함합니다. 이번 포스팅에서는 instanceof 연사자에 pattern matching 을 적용 하는 방법에 대해서 기술합니다.
jdk pattern matching
- jdk 14 버전에서 instanceof 연산자에 대한 pattern matching 기능이 JEP 305 를 통해 preview 기능으로 처음 제안됨
- jdk 16 버전에서 instanceof 연산자에 대한 pattern matching 기능이 JEP 394 를 통해 정식 기능으로 릴리즈됨
- jdk 17 버전에서 switch 표현식과 구문에 대한 pattern matching 기능이 JEP 406 을 통해 preview 기능으로 제안됨
pattern matching for instanceof
타입 패턴 형태로 타입 이름과 결과를 바인딩할 변수로 구성됩니다. instanceof 연산자에 타입 패턴을 적용하면 타입 체크와 형변환이 간소화됩니다.
아래와 같은 instanceof 에 대한 기존 코드가 있습니다.
if (obj instanceof String) {
String s = (String) obj;
....
}
위 코드에는 테스트(obj 가 String 타입인지?), 변환(obj 를 String 으로 형변환), 새로운 지역 변수 선언의 세 가지 작업을 수행합니다. 이미 obj 가 String 타입인지 테스트를 했음에도 명시적으로 형변환을 수행하는 것은 불필요 한 작업이 될 수 있습니다. 가장 중요한 것은 타입에 대한 테스트, 형변환, 지역변수 할당과 같은 반복으로 인해서 눈에 띄지 않는 오류를 발생 시킬 수 있다는 것입니다.
instanceof 에 대한 pattern matching 을 적용한 코드는 아래와 같습니다.
if (obj instanceof String s) {
//obj 를 String 타입 변수 s 에 할당한 s 를 사용
}
pattern matching 을 사용하게 되면 명시적인 형변환과 지역변수 정의 및 할당을 제거하여 코드를 간소화 시킬 수 있습니다.
scope of pattern variables
public interface Shape {}
public class Rectangle implements Shape {}
public class Circle implements Shape {}
public class Triangle implements Shape {}
...
if (shape instanceof Rectangle r) {
//Rectangle 타입의 패턴 변수 r 을 이 영역에서만 사용가능 합니다.
} else if (shape instanceof Circle c) {
//Circle 타입의 패턴 변수 c 는 이 영역에서만 사용가능 합니다.
//Rectangle 타입의 패턴 변수 r 은 이 영역에서는 사용할 수 없습니다.
} else {
//이 영역에서는 패턴 변수 r, c 모두 사용할 수 없습니다.
}
패턴 변수를 정의한 구문 밖으로 패턴 변수는 확장 될 수 있습니다.
public interface Shape {
void print();
}
public class Rectangle implements Shape {}
public class Circle implements Shape {}
public class Triangle implements Shape {}
...
void scopeTest(Shape shape) {
//if 블록 영역 밖이 Rectangle r 패턴 변수를 사용할 수 있는 영역입니다.
if (!(shape instanceof Rectangle r)) {
//Rectangle 타입의 패턴 변수 r 은 이 블록에서는 사용할 수 없습니다.
Sytem.out.println("rectangle 이 아닙니다.");
//하지만 아래 return 문이 없다면 if 블럭 밖에서 패턴 변수 r 을 사용할 수 없습니다.
//즉 패턴 변수 r 을 사용할 수 있는 영역과 아닌 영역이 명확하게 구분 되어야 합니다.
return;
}
//이 영역에서 패턴 변수 r 을 사용할 수 있습니다.
r.print();
}
=======================================================================
void scopeTest(Shape shape) {
if (!(shape instanceof Rectangle r)) {
//패턴 변수 r 을 사용할 수 없는 영역이기 때문에
//cannot find symbol (variable r) 오류 발생!!!
r.print();
}
}
=======================================================================
void scopeTest(Shape shape) {
if (!(shape instanceof Rectangle r)) {
Sytem.out.println("rectangle 이 아닙니다.");
}
//패턴 변수 r 을 사용할 수 없는 영역안에 return 문이 없기 때문에
//cannot find symbol (variable r) 오류 발생!!!
r.print();
}
if 문 안의 표현식에서 패턴 변수를 사용할 수 있습니다. 각 Rectangle, Triangle, Circle 클래스에 Boolean 타입을 리턴하는 isXXXX() 메소드가 있다고 가정합니다.
void scopeTest(Shape shape) {
//패턴 변수 r을 if문 내에서 사용할 수 있습니다.
if (shape instanceof Rectangle r && r.isShape()) {
r.print();
}
//패턴 변수 t를 if문 내에서 사용할 수 있습니다.
else if (shape instanceof Triangle t && t.isShape()) {
t.print();
}
//패턴 변수 c를 if문 내에서 사용할 수 있습니다.
else if (shape instanceof Circle c && c.isShape()) {
c.print();
} else {
throw new IllegalArgumentException();
}
}
void scopeTest2(Shape shape) {
// ||(or) 연사자를 통해서 shape 는 Rectangle 타입이 아닌 경우에도
// r.isShape() 이 호출되기 때문에 컴파일러 오류가 발생합니다. !!!
// cannot find symbol (variable r)
// symbol: variable r
if (shape instanceof Rectangle r || r.isShape()) {
...
}
}
'자바' 카테고리의 다른 글
Java - 람다 표현식 (lambda expression) 개요 (0) | 2023.09.10 |
---|---|
jdk pattern matching for switch (0) | 2023.08.26 |
java switch expression - from jdk 14 (0) | 2023.08.20 |
java Array vs ArrayList (0) | 2023.08.19 |
java record 용법 - from jdk 14 (0) | 2023.08.19 |
댓글