스위치가 열거 형인 경우 기본값의 사용법은 무엇입니까?
내가 열거 있다고 가정 Color
이 개 가능한 값을 : RED
및 BLUE
:
public enum Color {
RED,
BLUE
}
이제 두 가능한 값에 대한 코드가있는이 열거 형에 대한 switch 문이 있다고 가정합니다.
Color color = getColor(); // a method which returns a value of enum "Color"
switch (color) {
case RED:
...
break;
case BLUE:
...
break;
default:
break;
}
열거 형의 가능한 값 모두에 대한 코드 블록 default
이 있으므로 위 코드에서 사용되는 용도는 무엇 입니까?
코드가 default
이런 블록에 어떻게 든 도달하면 예외를 던져야 합니까?
Color color = getColor(); // a method which returns a value of enum "Color"
switch (color) {
case RED:
...
break;
case BLUE:
...
break;
default:
throw new IllegalArgumentException("This should not have happened");
}
두 번째 예제에서 보여준 것처럼 Exception을 던지는 것이 좋습니다. 빠르게 실패하여 코드의 유지 관리 성을 향상시킵니다.
이 경우 나중에 (아마도 몇 년 후) 열거 형 값을 추가하고 switch 문에 도달하면 즉시 오류를 발견하게됩니다.
기본값이 설정되지 않은 경우 새 열거 형 값을 사용해도 코드가 실행되고 원하지 않는 동작이 발생할 수 있습니다.
다른 대답은 default
나중에 새 값이 열거 형에 추가되는 경우 예외를 발생 시키는 분기를 구현해야한다는 점에서 정확 합니다. 그러나 나는 한 단계 더 나아가서 왜 당신이 switch
처음에 진술을 사용하고 있는지 의문을 품을 것입니다 .
C ++ 및 C #과 같은 언어와 달리 Java는 Enum 값을 실제 개체로 나타내므로 개체 지향 프로그래밍을 활용할 수 있습니다. 메서드의 목적이 각 색상에 대한 RGB 값을 제공하는 것이라고 가정 해 보겠습니다.
switch (color)
case RED:
return "#ff0000";
...
글쎄, 틀림없이 각 색상이 RGB 값을 갖기를 원한다면 설명의 일부로 포함해야합니다.
public enum Color
{
RED("#FF0000"),
BLUE("#0000FF");
String rgb;
public Color(String rgb) {
this.rgb = rgb;
}
public getRgb() { return this.rgb; }
}
이렇게하면 나중에 새 색상을 추가 할 경우 RGB 값을 제공해야합니다. 런타임이 아닌 컴파일 타임에 실패하기 때문에 다른 접근 방식보다 훨씬 빠르게 실패합니다.
필요한 경우 각 색상이 추상 메서드의 고유 한 사용자 지정 구현을 제공하도록하는 것을 포함하여 훨씬 더 복잡한 작업을 수행 할 수 있습니다. Java의 열거 형은 정말 강력하고 객체 지향적이며, 대부분의 경우 처음에 열거 할 필요가 없다는 것을 알았 switch
습니다.
스위치 케이스의 컴파일 시간 완전성은 런타임 완전성을 보장하지 않습니다.
이전 버전의 enum에 대해 컴파일 된 switch 문이있는 클래스는 최신 enum 버전 (더 많은 값 포함)으로 실행될 수 있습니다. 이는 라이브러리 종속성의 일반적인 경우입니다.
이와 같은 이유로 컴파일러는 대소 문자 switch
없이 default
불완전한 것으로 간주합니다 .
작은 프로그램에서는 실제로 사용할 수 없지만 많은 수의 파일과 개발자 사이에서 튀어 나오는 복잡한 시스템을 생각해보십시오 enum
. 한 파일에서 정의하고 다른 파일에서 사용하고 나중에 누군가가 값을 추가하는 경우 는 enum
업데이트하지 않고 switch
문을, 당신은 매우 유용 할 것입니다 ...
당신이 당신의 다양한으로 모든 가능성을 다룬 경우 cases
와는 default
일어날 수없는,이에 대한 고전적인 사용 사례입니다 주장 :
Color color = getColor(); // a method which returns a value of enum "Color"
switch (color) {
case RED:
// ...
break;
case BLUE:
// ...
break;
default:
assert false; // This cannot happen
// or:
throw new AssertionError("Invalid Colors enum");
}
IDE 및 기타 정적 린터를 충족하기 위해 종종 // Can't happen
또는 같은 주석과 함께 기본 케이스를 no-op으로 남겨 둡니다.// Unreachable
즉, 스위치가 명시 적으로 또는 폴 스루를 통해 가능한 모든 열거 형 값을 처리하는 일반적인 작업을 수행하는 경우 기본 사례는 아마도 프로그래머 오류 일 것입니다.
응용 프로그램에 따라 개발 중에 프로그래머 오류를 방지하기 위해 경우에 따라 어설 션을 넣는 경우가 있습니다. 그러나 이것은 배송 코드의 가치가 제한적입니다 (어설 션이 활성화 된 상태로 배송하지 않는 한).
다시 말하지만 상황에 따라 오류를 던질 수 있습니다. 이것은 실제로 복구 할 수없는 상황이기 때문입니다. 사용자가 할 수있는 일은 프로그래머 오류 일 가능성이있는 오류를 수정할 수 없습니다.
예,해야합니다. 당신은 변할 수 enum
있지만 변할 수는 없습니다 switch
. 미래에는 실수로 이어질 것입니다. 그게 throw new IllegalArgumentException(msg)
좋은 습관 이라고 생각합니다 .
열거 형 상수가 너무 많고 소수의 경우에만 처리해야하는 경우 default
나머지 상수는에서 처리합니다.
또한 열거 형 상수는 참조가 아직 설정되지 않은 경우 참조이거나 null
. 이러한 경우도 처리해야 할 수 있습니다.
예, 누군가 enum에 값을 추가하기 전까지는 죽은 코드입니다. 그러면 switch 문이 'fail fast'( https://en.wikipedia.org/wiki/Fail-fast ) 원칙을 따릅니다.
이것은 다음 질문과 관련 될 수 있습니다. 컴파일 타임에 열거 형 스위치의 완전성을 보장하는 방법은 무엇입니까?
많은 사람들이 지적한 열거 형의 미래 확장 가능성 외에도 언젠가 누군가가 당신을 '개선' getColor()
하거나 파생 클래스에서 재정의하고 잘못된 값을 반환하도록 할 수 있습니다. 물론 누군가가 명시 적으로 안전하지 않은 유형 캐스팅을 강요하지 않는 한 컴파일러는이를 포착해야합니다.
그러나 나쁜 일이 일어나기 때문에 예상치 못한 경로 else
나 default
경로를 방치 하지 않는 것이 좋습니다 .
아무도 이것을 언급하지 않은 것에 놀랐습니다. int를 열거 형으로 캐스팅 할 수 있으며 값이 열거 형 값 중 하나가 아니기 때문에 던지지 않습니다. 즉, 컴파일러는 모든 열거 형 값이 스위치에 있음을 알 수 없습니다.
Even if you write your code correctly, this really does come up when serializing objects that contain enums. A future version might add to the enum and your code choke on reading it back, or somebody looking to create mayhem may hexedit a new value in. Either way, running off the switch rarely does the right thing. So, we throw in default unless we know better.
Here is how I would handle it, beside NULL
value which would result in a null pointer exception which you can handle.
If Color color
is not null
, it has to be one of the singletons in enum Color
, if you assign any reference to an object that is not one of the them this will cause a Runtime error.
So my solution is to account for values that are not supported.
Test.java
public Test
{
public static void main (String [] args)
{
try { test_1(null); }
catch (NullPointerException e) { System.out.println ("NullPointerException"); }
try { test_2(null); }
catch (Exception e) { System.out.println(e.getMessage()); }
try { test_1(Color.Green); }
catch (Exception e) { System.out.println(e.getMessage()); }
}
public static String test_1 (Color color) throws Exception
{
String out = "";
switch (color) // NullPointerException expected
{
case Color.Red:
out = Red.getName();
break;
case Color.Blue:
out = Red.getName();
break;
default:
throw new UnsupportedArgumentException ("unsupported color: " + color.getName());
}
return out;
}
.. or you can consider null
as unsupported too
public static String test_2 (Color color) throws Exception
{
if (color == null) throw new UnsupportedArgumentException ("unsupported color: NULL");
return test_1(color);
}
}
Color.java
enum Color
{
Red("Red"), Blue("Blue"), Green("Green");
private final String name;
private Color(String n) { name = n; }
public String getName() { return name; }
}
UnsupportedArgumentException.java
class UnsupportedArgumentException extends Exception
{
private String message = null;
public UnsupportedArgumentException() { super(); }
public UnsupportedArgumentException (String message)
{
super(message);
this.message = message;
}
public UnsupportedArgumentException (Throwable cause) { super(cause); }
@Override public String toString() { return message; }
@Override public String getMessage() { return message; }
}
In this case using Assertion in default is the best practice.
'code' 카테고리의 다른 글
C 면접-캐스팅 및 비교 (0) | 2020.12.06 |
---|---|
Swift에서 Return 키를 누르면 텍스트 필드 간 전환 (0) | 2020.12.06 |
반응 구성 요소에서 CSS 파일을 가져 오는 방법은 무엇입니까? (0) | 2020.12.06 |
유닉스 시스템에서 바이너리 파일을 편집하는 방법 (0) | 2020.12.06 |
오늘 자정에 NSDate 객체를 어떻게 얻을 수 있습니까? (0) | 2020.12.06 |