열거 형이 문자열 표현을 더 간단하게 만들기 위해 모든 대문자 이름을 지정해도 괜찮습니까?


14

여러 번 사람들이 열거 형 상수에 제목 대소 문자 또는 모든 소문자 이름을 사용하는 것을 보았습니다.

enum Color {
  red,
  yellow,
  green;
}

throw new IllegalStateException("Light should not be " + color + ".")예를 들어 문자열 형식으로 작업하는 것이 간단하고 쉽습니다 .

열거 형이 private인 경우 더 받아 들일 수 있지만 여전히 마음에 들지 않습니다. String 필드를 사용하여 열거 형 생성자를 만든 다음 toString을 재정 의하여 다음과 같이 해당 이름을 반환 할 수 있습니다.

enum Color {
  RED("red"),
  YELLOW("yellow"),
  GREEN("green");

  private final String name;

  private Color(String name) { 
    this.name = name 
  }

  @Override public String toString() {
    return name; 
  }
}

그러나 그것이 얼마나 더 긴지보십시오. 간단하게 유지하려는 작은 열거 형이 있으면 계속하는 것이 짜증납니다. 여기에 틀에 맞지 않는 케이스 형식을 사용하는 것이 좋습니까?


4
컨벤션입니다. 컨벤션을 깰 이유가 있습니까? 그것은 당신에게 달려 있습니다.

9
라는 예외 메시지에 무엇이 문제인지 궁금합니다 Light should not be RED.. 결국,이 메시지는 개발자를위한 것이므로 사용자는 절대 볼 수 없습니다.
Brandin

1
@Brandin 색상이 구현 세부 사항에 가깝다면 아무도 볼 수 없습니다. 물론, 왜 멋진 toString 형식이 필요한지에 대한 의문이 남는 것 같습니다.
codebreaker

8
하루가 끝나면 그것은 당신에게 달려 있습니다. 코드를 디버깅하고 예외 메시지를 보았을 때 Light should not be YELLOW.그것이 일종의 상수라고 생각할 것입니다 .toString () 메서드는 디버깅 목적으로 만 사용되므로 해당 메시지의 모양을 변경 해야하는 이유를 알 수 없습니다.
Brandin

1
답은 '괜찮아'라는 생각에 더 근거가 있다고 생각합니다. 이렇게하면 세상이 화염에 휩싸이지 않고 프로그램을 성공적으로 작성할 수있을 것입니다. 유용합니까? meh도 너무 주관적입니다. 혜택을 받으면 그만한 가치가 있으며 다른 사람들에게도 영향을 미칩니 까? 이것들은 내가 관심있는 질문입니다.
Garet Claborn

답변:


14

물론 짧은 대답은 본질적으로 상수에 대한 명명 규칙을 어길 것인지 여부입니다. JLS 에서 인용 :

상수 이름

인터페이스 유형의 상수 이름은 클래스 유형의 최종 변수 여야하며, 일반적으로 밑줄 "_"문자로 구분 된 구성 요소를 갖는 하나 이상의 단어, 두문자어 또는 약어가 모두 대문자 일 수 있습니다. 상수 이름은 설명이 필요하며 불필요하게 축약되어서는 안됩니다. 통상적으로 그것들은 적절한 말의 일부일 수있다.

의 사용과 관련하여 긴 대답 toString()은 더 읽기 쉬운enum 값 표현을 원한다면 분명히 재정의하는 방법 입니다. 인용 Object.toString()(강조 광산) :

객체의 문자열 표현을 반환합니다. 일반적 으로이toString 메서드는 이 객체를 "텍스트로 표현" 하는 문자열을 반환 합니다 . 결과는 사람이 읽기 쉬운 간결하지만 유익한 표현이어야합니다 . 모든 서브 클래스가이 메소드를 대체하는 것이 좋습니다.

이제 왜 일부 답변이 값으로 변환 enums하는 것에 대해 표류했는지에 대해서는 잘 모르겠지만 String여기서도 설명하겠습니다. 이러한 enum값의 직렬화 는 name()또는 ordinal()방법 을 사용하여 쉽게 처리 할 수 ​​있습니다 . final의 이름이나 위치가 변경되지 않는 한 모두 반환 된 값을 확인할 수 있습니다 . 나에게, 그것은 충분히 명확한 마커입니다.

내가 위에서 수집 한 것은 : 오늘, 당신은 YELLOW단순히 "노란색" 으로 묘사하고 싶을 것 입니다. 내일, 당신은 그것을 "Pantone Minion Yellow"라고 묘사하고 싶을 것 입니다. 이 설명은을 호출하여 반환해야하며 또는 변경 toString()될 것으로 기대하지 않습니다 . 그렇다면 코드베이스 또는 팀 내에서 해결해야 할 문제 이며 이름 지정 스타일 보다 더 큰 질문이 됩니다.name()ordinal()enum

결론적으로, 당신이하려는 모든 것이 더 읽기 쉬운enum 값의 표현 을 기록하는 것이라면 , 나는 여전히 규칙을 고수하고 재정의하는 것이 좋습니다 toString(). 데이터 파일 또는 Java 이외의 다른 대상으로 직렬화하려는 경우에도 여전히 백업 할 수 있는 name()ordinal()메소드가 있으므로 재정의를 걱정할 필요가 없습니다 toString().


5

ENUM코드 냄새가 나쁘다는 것을 수정하지 마십시오 . 열거 형은 열거 형이고 문자열은 문자열입니다.

대신 문자열 값에 CamelCase 변환기를 사용하십시오.

throw new IllegalStateException("Light should not be " + CamelCase(color) + ".");

Java에 대해이 문제를 이미 해결 한 많은 오픈 소스 라이브러리가 있습니다.

http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/CaseFormat.html


특정 경우에 비 결정적이지 않습니까? (특정 변환기의 행동이 아니라 일반적인 원리)
Panzercrisis

-1 기본 문자열 형식에 적합하지 않을 수있는 타사 라이브러리를 추가하면 과도 할 수 있습니다.
user949300 2016 년

1
@ user949300 코드를 복사하고 직접 작성하십시오. 요점이 없습니다.
Reactgular

"요점"에 대해 자세히 설명해 주시겠습니까? "열거 형이 열거 형이고 문자열이 문자열이되게하라"는 말이 좋지만 실제로 무엇을 의미합니까?
user949300

1
열거 형은 형식 안전성을 제공합니다. 그는 "감자"를 색으로 전달할 수 없습니다. 그리고 아마도 그는 RGB 값과 같은 열거 형의 다른 데이터를 코드에 표시하지 않을 것입니다. 문자열 대신 열거 형을 사용해야하는 많은 이유가 있습니다.
user949300

3

Java 코드와 데이터베이스 또는 클라이언트 응용 프로그램 사이에 열거 형을 보내면 종종 열거 형 값을 읽고 문자열로 작성합니다. toString()문자열을 연결할 때 암시 적으로 호출됩니다. 일부 열거 형에서 toString ()을 재정의하면 때로는

"<input type='checkbox' value='" + MY_CONST1 + "'>"

때로는 전화를 기억해야했습니다

"<input type='checkbox' value='" + MY_CONST1.name() + "'>"

오류가 발생하여 더 이상 그렇게하지 않습니다. 사실, 오버라이드 (override)하지 않는 어떤 충분한 클라이언트 코드에 주위에 던져, 당신은 결국 사람의 기대를 깰 것이기 때문에 열거 메소드를.

처럼, 자신의 새로운 방법 이름을 확인 public String text()하거나 toEnglish()또는 무엇 이건.

위와 같은 열거 형이 많으면 타이핑을 줄일 수있는 작은 도우미 기능이 있습니다.

public static String ucFirstLowerRest(String s) {
    if ( (s == null) || (s.length() < 1) ) {
        return s;
    } else if (s.length() == 1) {
        return s.toUpperCase();
    } else {
        return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
    }
}

항상 .toUpperCase () 또는 .toLowerCase ()를 호출하는 것은 쉽지만 대소 문자를 혼합하는 것은 까다로울 수 있습니다. "블루 드 프랑스"의 색상을 고려하십시오. 프랑스는 항상 대문자로 표시되므로 열거 형에 textLower () 메서드를 추가하려는 경우가 있습니다. 문장의 시작 부분, 문장 중간, 제목에서이 텍스트를 사용하면 단일 toString()방법이 어떻게 부족 한지 알 수 있습니다 . Java 식별자에서 불법이거나 표준 키보드로 표시되지 않아 입력하기가 어려운 문자 또는 대소 문자가없는 문자 (한자 등)를 만지지 않습니다.

enum Color {
  BLEU_DE_FRANCE {
    @Override public String textTc() { return "Bleu De France"; }
    @Override public String textLc() { return "bleu de France"; }
  }
  CAFE_NOIR {
    @Override public String textTc() { return "Café Noir"; }
  }
  RED,
  YELLOW,
  GREEN;

  // The text in title case
  private final String textTc;

  private Color() { 
    textTc = ucFirstLowerRest(this.toString());
  }

  // Title case
  public String textTc() { return textTc; }

  // For the middle of a sentence
  public String textLc() { return textTc().toLowerCase(); }

  // For the start of a sentence
  public String textUcFirst() {
    String lc = textLc();
    return lc.substring(0, 1).toUpperCase() + lc.substring(1);
  }
}

이것을 올바르게 사용하는 것은 어렵지 않습니다.

IllegalStateException(color1.textUcFirst() + " clashes horribly with " +
                      color2.textLc() + "!")

희망에 따라 대소 문자 열거 형 값을 사용하면 왜 실망하는지 알 수 있습니다. 밑줄 열거 형 상수가있는 모든 대문자를 유지해야하는 마지막 한 가지 이유는 가장 작은 놀라움의 원리를 따르는 것입니다. 사람들은 그것을 기대하기 때문에 다른 일을한다면 항상 자신을 설명하거나 코드를 잘못 사용하는 사람들을 대해야 할 것입니다.


3
toString()열거 형에서 재정의하지 않는 제안 은 의미가 없습니다. 열거 형 이름의 기본 동작을 보장하려면을 사용하십시오 name(). 에 toString()대한 올바른 키를 제공하기 위해 "시도"하는 것은 아닙니다 valueOf(String). 나는 당신이 당신의 열거 형을 바보 증거로 만들고 싶다면, 그것이 한 가지 일 것입니다. 그러나 그것이 결코 무시 해서는 안된다고 권고할만한 충분한 이유라고 생각하지 않습니다 toString().
codebreaker

1
: 또한, 내가 열거에 toString를 오버라이드 (override)하는 것은 사실 좋은 일입니다 (나는 믿게되면서) 권장되는이 발견 stackoverflow.com/questions/13291076/...
codebreaker

문자열을 연결할 때 @codebreaker toString ()이 암시 적으로 호출됩니다. 일부 열거 형에서 toString ()을 재정의하면 때로는 그냥 할 수 <input type='checkbox' value=" + MY_CONST1 + ">있고 때로는 호출해야 한다는 것을 의미 <input type='checkbox' value=" + MY_CONST1.name() + ">하여 오류가 발생했습니다.
GlenPeterson

좋아, 그것은 좋은 지적이지만, 당신이 그들의 이름으로 열거 형을 "직렬화"할 때만 중요합니다 (내 예제에서 걱정할 필요는 없습니다).
codebreaker 2016 년

0

이러한 문자열 표현이 데이터베이스 나 텍스트 파일과 같은 장소에 저장 될 가능성이 가장 적다면, 열거 형을 리팩토링해야하는 경우 실제 열거 형 상수에 묶여있는 것이 매우 문제가됩니다.

만약에 당신의 이름을 변경하기로 결정 일일 Color.WhiteColor.TitaniumWhite데이터가 "화이트"를 포함하는 거기 파일이있는 동안?

또한 열거 형 상수를 문자열로 변환하기 시작하면 다음 단계는 사용자가 볼 수있는 문자열을 생성하는 것입니다. 이미 문제는 이미 알고 있듯이 Java 구문이 식별자 내에 공백을 허용하십시오. (당신은하지 않습니다 Color.Titanium White.) 그래서, 당신은 아마 사용자에게 보여 열거 이름을 생성하기위한 적절한 메커니즘이 필요하기 때문에, 그것은 당신의 열거 복잡 불필요하게하지 않도록하는 것이 가장 좋습니다.

이미 말했듯이, 당신은 계속해서 생각하고있는 일을 한 다음 나중에 열거 형을 리팩터링하여 이름을 생성자에게 전달하기 위해 이름을 전달할 수 있습니다.

name필드 를 선언 public final하고 게터를 잃어 버리면 생성자와 열거 자에서 몇 줄을 면도 할 수 있습니다 . (자바 프로그래머가 게터를 향한 사랑은 무엇인가?)


public final static은 생성 된 클래스에 대한 참조가 아니라 실제 상수로 사용하는 코드로 컴파일됩니다. 이로 인해 코드의 부분 재 컴파일을 수행하거나 항아리를 교체 할 때 여러 가지 재미있는 오류가 발생할 수 있습니다. 당신이 제안하는 경우 public final static int white = 1;또는 public final static String white = "white";(다시 규칙의 파괴 제외)이 열거가 제공하는 유형의 안전을 잃는다.

@MichaelT Enum 필드는 정적이 아닙니다. 각 열거 형 상수에 대해 인스턴스가 생성되며 열거 형의 멤버는 해당 인스턴스의 멤버 변수입니다. public final생성자에서 초기화 된 인스턴스 필드 는 컴파일 타임에 할당 할 수 없다는 점을 제외하면 최종 필드가 아닌 필드와 똑같이 동작 합니다. 리플렉션을 통해 수정할 수 있으며이를 참조하는 모든 코드는 즉시 새 값을 보게됩니다.
Mike Nakis

0

아마도 대문자 이름 지정 규칙을 따르는 것은 DRY를 위반 합니다. (그리고 YAGNI ). 예를 들어, 코드 예제 # 2에서 : "RED"와 "red"가 반복됩니다.

공식적인 규칙을 따르거나 DRY를 따르십니까? 당신의 전화.

내 코드에서는 DRY를 따릅니다. 그러나 Enum 클래스에 대해서는 "대문자 (설명) 때문에 모든 대문자가 아닌"

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.