2012년 5월 19일 토요일

Java7에서 개선된 언어기능: 문자열을 위한 switch 구문개선


Java7에 추가된 Java 언어의 7가지 개선사항 중 본 포스트에서는 "Strings in 'switch' statements"에 대해 정리하고, 몇 가지 주의사항에 대해 언급하겠습니다. 7가지 개선사항은 다음과 같습니다.(OpenJDK: "Project Coin", JSR-334)
  • Binary Literals
  • Underscores in Numeric Literals
  • Strings in switch Statements
  • The try-with-resources Statement
  • Catching Multiple Exception Types and Rethrowing Exceptions with Improved Type Checking
  • Type Inference for Generic Instance Creation
  • Improved Compiler Warnings and Errors When Using Non-Reifiable Formal Parameters with Varargs Methods



Java7의 Language Specification에 기술된 switch 문장의 구문은 다음과 같습니다.
SwitchStatement:
    switch ( Expression )
        SwitchBlock
Expression에는 char, byte, short, int, Character, Byte, Short, Integer, String 그리고 enum 타입이 올 수 있으며, 기존에 허용되지 않던 String 타입이 추가되었습니다.

Java7 이전에는 switch 문장에서 String 타입 표현식을 허용하지 않았기 때문에 다중 if-else 문장으로 처리할 수 밖에 없었습니다.
public void withoutString(String str) {

    if(str.equals("bob") || str.equals("sam"))
        //do something ...
    else if(str.equals("carl") || str.equals("joy"))
        //do something ...
    else if(str.equals("anna") || str.equals("haron"))
        //do something ...
    else
        //do something ...

}
위 코드를 switch 문장으로 옮기면 다음과 같습니다.
public void withString(String str) {
    
    switch(str) {
        case "bob": case "sam":
          //do something ...
          break;
        case "carl": case "joy":
          //do something ...
          break;
        case "anna": case "haron":
          //do something ...
          break;
        default:
          //do something ...
    }

}
두 코드를 비교해 보면 if-else 문장의 경우 매번 String 클래스의 equals() 메서드로 문자열을 비교해야하는 번거로움이 있음을 알 수 있습니다.

개인적으로는 개선된 기능을 통해 코드의 가독성이 좋아졌다고 생각되나 주의해야 할 점이 있습니다.
  • 표현식에 사용되는 String 객체가 null인지 확인해야 함
  • String 비교시 대소문자 구분("Sam"과 "sam"은 다른 객체)
  • 오직 String 타입의 참조변수만 허용

첫 번째 주의할 사항은 바로 표현식에 사용되는 str이 null인 경우입니다. if-else 문장에서 문자열을 비교하는 equals() 메서드 호출도 null.equals()는 NullPointerException에 해당합니다. 이러한 경우 null 문자열와의 비교는 항상 false를 반환하도록 다음과 같은 트릭을 사용하여 NullPointerException을 방지할 수 있습니다.
if("bob".equals(str) || ...

Java7의 switch 문장의 경우, 다음 코드와 같이 case문에서 null 상수를  사용할 수 없기때문에 적절한 전처리가 필요합니다.
    switch(str) {

        case null: //ERROR!!
            .....
            break;

        case "bob": case "sam":
            System.out.println("bob or sam");
            break;

        default:
           System.out.println("default");
           break;
    }

두 번째 사항은 문자열 객체의 대소문자 구분에 관한 내용이고, 마지막으로 오직 String 타입만 Expression에서 허용되므로 다음과 같은 코드는 컴파일에러입니다.
public void switchTest() {

    //OK: "bob" is-a Object!!
    Object str = "bob";

    //ERROR!!
    switch(str) {
        ...
    }
}

참고로 switch 문장에서 String 타입이 지원되기까지 대략16년 정도 걸렸다고 합니다. 1995년에 보고된 다음 Bug 리포트를 참조해 보시기 바랍니다.

[참고문헌]
1. Java Magazine 2011 Premiere
2. Java SE 7 Features and Enhancements


댓글 5개:

  1. 작성자가 댓글을 삭제했습니다.

    답글삭제
  2. 재밋네요 :D
    왜이렇게 늦게 지원하게 되었을까요?
    기술적인 문제 vs 철학적인 문제
    아니면 그냥 귀찮앗는지.. ㅎㅎ

    답글삭제
    답글
    1. 예전보다 성능이 많이 좋아져서 trade-off 할 수 있게 된것 때문이 아닐까요?
      https://namocom.tistory.com/653

      삭제