- JEP 305 in Java 14
- JEP 375 in Java 15
- JEP 394 in Java 16
- 어떤 객체가 특정 타입인지의 여부를 확인하는 코드는 자주 사용됨
- 특정 타입인지 확인하고
- 캐스팅하고
- 그 값을 새로운 변수에 정의해야 함
instanceof-and-cast
idiom
if (obj instanceof String) {
String s = (String) obj; // grr...
...
}
- 어떤 객체의 형태가 간결하게
패턴
으로 표현되도록 하고, 입력에 대해 그 형태가 매칭
되는지 확인하는 것
- 문자열 패턴매칭: 정규표현식 패턴매칭이나 globbing 패턴 매칭
- 객체 타입 패턴매칭
- 패턴
- predicate or test: 대상에 적용할 수 있는 조건
- 지역 변수의 집합: 조건이 만족되었을 때 대상으로부터 추출 가능한 패턴 변수
타입 패턴
- 타입을 명세하는 predicate
단일 패턴 변수
- instanceof 연산자가 특정 타입 하나가 아니라 타입 패턴에 대응되도록 확장됨
if (obj instanceof String s) {
// Let pattern matching do the work!
...
}
- 객체가 특정 타입과 일치하면 캐스팅과 변수 선언 및 초기화까지 처리됨
if (a instanceof Point p) {
// p is in scope
...
}
// p not in scope here
if (b instanceof Point p) { // Sure!
...
}
if (obj instanceof String s && s.length() > 5) {
flag = s.contains("jdk");
}
if (obj instanceof String s || s.length() > 5) { // Error!
...
}
public void onlyForStrings(Object o) throws MyException {
if (!(o instanceof String s))
throw new MyException();
// s is in scope
System.out.println(s);
...
}
class Example1 {
String s;
void test1(Object o) {
if (o instanceof String s) {
System.out.println(s); // Field s is shadowed
s = s + "\n"; // Assignment to pattern variable
...
}
System.out.println(s); // Refers to field s
...
}
}
¶ 변수 shadowing에 주의할 것
class Example2 {
Point p;
void test2(Object o) {
if (o instanceof Point p) {
// p refers to the pattern variable
...
} else {
// p refers to the field
...
}
}
}
public boolean equals(Object o) {
return (o instanceof CaseInsensitiveString) &&
((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
}
public boolean equals(Object o) {
return (o instanceof CaseInsensitiveString cis) &&
cis.s.equalsIgnoreCase(s);
}
public boolean equals(Object o) {
if (!(o instanceof Point))
return false;
Point other = (Point) o;
return x == other.x
&& y == other.y;
}
public boolean equals(Object o) {
return (o instanceof Point other)
&& x == other.x
&& y == other.y;
}
String formatted = "unknown";
if (obj instanceof Integer) {
int i = (Integer) obj;
formatted = String.format("int %d", i);
} else if (obj instanceof Byte) {
byte b = (Byte) obj;
formatted = String.format("byte %d", b);
} else if (obj instanceof Long) {
long l = (Long) obj;
formatted = String.format("long %d", l);
} else if (obj instanceof Double) {
double d = (Double) obj;
formatted = String.format("double %f", d);
} else if (obj instanceof String) {
String s = (String) obj;
formatted = String.format("String %s", s);
}
String formatted =
switch (obj) {
case Integer i -> String.format("int %d", i);
case Byte b -> String.format("byte %d", b);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s, s);
default -> String.format("Object %s", obj);
};
- 현재는 향후 계획으로 잡혀 있는 기능이라서 현재 버전의 JDK와 IntelliJ에서는 지원되지 않음
interface Node {
int eval();
}
class IntNode implements Node {
int value;
int eval() { return value; }
}
class NegNode implements Node {
Node node;
int eval() { return -node.eval(); }
}
class MulNode implements Node {
Node left, right;
int eval() { return left.eval() * right.eval(); }
}
class AddNode implements Node {
Node left, right;
int eval() { return left.eval() + right.eval(); }
}
int eval(Node n) {
return switch(n) {
case IntNode(int i) -> i;
case NegNode(Node n) -> -eval(n);
case AddNode(Node left, Node right) -> eval(left) + eval(right);
case MulNode(Node left, Node right) -> eval(left) * eval(right);
};
}
patternmatch.zip