왜 당신의 switch 문 데이터 유형이 길지 않습니까, Java?


80

다음은 Sun의 Java 자습서 에서 발췌 한 것입니다 .

스위치는 작동 byte, short, char, 및 int기본 데이터 형. 또한 특정 기본 유형을 "포장"고 (클래스와 상속에서 논의) 열거 유형과 몇 가지 특별한 클래스와 함께 작동 : Character, Byte, Short,과 Integer(단순 데이터 개체에서 논의).

long기본 데이터 유형이 허용되지 않는 이유가 있어야합니다 . 누구든지 그것이 무엇인지 압니까?

답변:


52

일반적인 스위치 사용을 기반으로 한 임의의 결정이라고 생각합니다.

스위치는 기본적으로 두 가지 방법 (또는 원칙적으로 조합)으로 구현 될 수 있습니다. 소수의 경우 또는 값이 광범위하게 분산 된 경우 스위치는 기본적으로 임시 변수에 대한 일련의 if와 동일합니다. 켜진 값은 한 번만 평가해야합니다). 값이 다소 연속적인 적당한 수의 경우에는 스위치 테이블 (Java의 TABLESWITCH 명령어)이 사용되어 점프 할 위치가 테이블에서 효과적으로 조회됩니다.

이 방법 중 하나는 원칙적으로 정수가 아닌 긴 값을 사용할 수 있습니다. 하지만 명령 세트와 컴파일러의 복잡성과 실제 요구 사이의 균형을 맞추는 것은 아마도 실용적인 결정이라고 생각합니다. 실제로 긴 시간을 전환해야하는 경우는 드물기 때문에 A로 다시 작성해야합니다. 일련의 IF 문을 사용하거나 다른 방식으로 작업합니다 (문제의 긴 값이 서로 가깝다면 Java 코드에서 가장 낮은 값을 뺀 int 결과로 전환 할 수 있습니다).


나는 한동안 Java로 개발해 왔기 때문에 "희귀 성"주장에 동의해야하며 지금까지 오랫동안 스위치를 켜고 시도한 상황을 본 적이 없습니다.
Fostah 2010

3
디미트리 스, 내 추론은 스레드 안전성에 대한 오해에 근거한 것이 아니라 당신이 제시 한 스레드 안전성 주장이 성립하지 않는다고 생각합니다.
Neil Coffey

13
가장 어리석은 디자인 결정. 나는 긴 깃발을 가지고 있고, if ... else if ... else ... 완전히 우스꽝 스럽습니다.
m0skit0

2
@ m0skit0에 동의합니다. 제 경우에는 다른 누군가가 longs를 상수로 사용하는 API를 작성했습니다. DB에 저장하는 것이기 때문입니다. 이제 다른 사람의 잘못된 결정으로 인해 스위치 / 케이스를 사용할 수 없습니다.
CodeChimp

1
나는 그것이 "세상의 종말"이라고 말하는 것이 아닙니다. 그리고 예, 주위에 방법이 있지만 모두 해킹처럼 보입니다. 내 요점은 개발자로서 우리는 항상 사람들이 우리가 만든 것을 사용할 것이라고 생각하는 과거를 생각해야한다는 것입니다. 이 경우 누군가 "솔직히 2 ^ 64 건을 가질 것"이라는 초기 생각을 바탕으로 오랫동안 전환 / 케이스를 허용하지 않기로 결정했습니다. 아마도 그것은 지나치게 단순화 된 것입니다. 아마도 우리가 프라이 비가 아니었기 때문에 롱스를 전환 할 수없는 다른 이유가있을 수 있습니다. 나에게는 그것을 지원하지 않는 것이 이상하게 보입니다.
CodeChimp

21

그들은 바이트 코드에서 필요한 지침을 구현하지 않았고 당신 때문에 정말 많은 경우, "제작 준비"코드가 얼마나 상관없이 쓰고 싶지 않아 ...

[편집 :이 답변에 대한 의견에서 추출, 배경에 대한 추가 사항 포함]

정확히 말하면, 2³²는 많은 경우이며 그 이상을 저장할 수있는 방법을 가진 프로그램은 완전히 끔찍할 것입니다! 모든 언어로. (어떤 언어의 어떤 코드에서든 내가 아는 가장 긴 함수는 6k SLOC를 약간 넘는 것입니다. 예, 그것은 크며 switch정말 관리하기 어렵습니다.) 만약 당신이 하나 이하 long만 가져야 하는 곳에 집착한다면 int, 두 가지 실제 대안이 있습니다.

  1. 해시 함수 테마에 대한 몇 가지 변형을 사용 long하여 int. 가장 간단한 방법은 유형이 잘못되었을 때만 사용하는 것입니다. 더 유용한 방법은 다음과 같습니다.

    (int) ((x&0xFFFFFFFF) ^ ((x >>> 32) & 0xFFFFFFFF))
    

    결과를 켜기 전에. 테스트 대상 케이스를 변환하는 방법도 알아 내야합니다. 그러나 실제로는 많은 경우의 실제 문제를 다루지 않기 때문에 여전히 끔찍합니다.

  2. 매우 많은 수의 케이스로 작업하는 경우 훨씬 더 나은 솔루션 Map<Long,Runnable>은 특정 값을 전달하는 방법을 찾을 수 있도록 a 또는 유사한 것을 사용하도록 설계를 변경하는 것입니다. 이를 통해 케이스를 여러 파일로 분리 할 수 ​​있습니다. 이는 케이스 수가 커지면 관리하기가 훨씬 더 쉽습니다.하지만 관련된 구현 클래스의 호스트 등록을 구성하는 것이 더 복잡해집니다 (주석은 다음을 허용함으로써 도움이 될 수 있습니다. 자동으로 등록 코드 작성).

    FWIW, 저는 수년 전에 대규모 병렬 하드웨어를 시뮬레이션하기위한 커스텀 바이트 코드 엔진을 구축 할 때 (프로젝트를 통해 새로 출시 된 J2SE 1.2로 전환했습니다)이 작업을 수행했습니다 (아니요, JVM 재사용은 근본적으로 다른 값과 실행 모델이 포함되어 있음) switchC 버전의 코드가 사용 하는 큰 코드에 비해 코드가 엄청나게 단순화 되었습니다.

하고 싶은, 테이크 가정 메시지를 반복하려면 switchA가에 long하나 당신이 당신의 프로그램 또는 당신이 클래스를 사용하는 것을 포함하는 많은 변화가있는 시스템을 구축하고 그 유형이 잘못 가지고 있다는 표시입니다. 두 경우 모두 재고 할 시간입니다.


1
그러나 범위가 실제로 32 비트 이상으로 전환되고 있습니까? 많은 스위치 암이 필요한 코드는 들어 본 적이 없습니다. 그것 없이는 범위를 압축 할 수 있습니다 (예를 들어, 해시 함수의 테마에 약간의 변형을 사용하여) 작동하는 것을 만들 수 있습니다. 또는 a Map<Long,Runnable>를 사용하여 완전히 다른 방식으로 문제를 해결하십시오. :-)
Donal Fellows

3
@Lord Torgamus : 아마도 어리석기 때문일 것입니다. 잠시 생각해 왜 사람이, 할 사람이 , 2 개 이상의와 코드가 A의 32 팔을 switch? 그 많은 요소의 유한 한 세트를 선택하려는 것은 단순히 프로그램의 기본 설계의 실수를 가리 킵니다. 사람들이 그것을 요구한다는 것은 단지 ** 그들의 디자인이 잘못되었다는 것을 나타냅니다 .
Donal Fellows

1
BTW, 누군가 나와 이것에 대해 더 논쟁하고 싶다면 long을 켜는 사용 사례를 제공하여 시작하십시오. 그렇지 않으면 우리는 영원히 가설과 논쟁을 벌일 것입니다 ...
Donal Fellows

2
@DonalFellows, 또 다른 경우는 ListView와 함께 Android에 있습니다. listViews는 long행 수를 가질 수 있지만 특별히 4 개만 필요합니다. 이것은 long어떤 행이 실행되고 있는지를 나타내는 나에게 손을 줬던 경우이며, 어떤 행인지에 따라 다른 작업을 수행해야합니다. 나는 int로 캐스트 할 수 있다고 생각하지만 switch, 변수를 그냥 편집 할 수 있었다면 내 인생을 더 쉽게 만들었을 것 입니다. 그대로 if, else if대신 문자열을 사용하고 있습니다.
기독교 스미스

7
"취소 메시지를 되풀이하자면, 긴 스위치를 켜고 싶다는 것은 프로그램에 잘못된 유형이 있음을 나타내는 것입니다." -아닙니다. a long가 있다고해서 모든 가능성을 확인 한다는 의미는 아닙니다 . int또는 a String가 있다고해서 그 중 하나를 의미 하는 것은 아닙니다. 소수 일 수있는 값이 큰 범위 를 가짐을 의미합니다 . 몇 가지 간단한 사례를 확인 default하고 나머지는 속할 수 있습니다. 교대와 캐스트를해야한다는 것은 데이터 손실 위험이 있다는 것을 의미합니다. 결론은 사용자 문제가 아닌 잘못된 Java 설계 결정입니다.
jbx

6

조회 테이블 인덱스는 32 비트 여야하기 때문입니다.


3
그러나 switch룩업 테이블을 반드시 구현할 필요는 없습니다.
Joachim Sauer

10
그럴 경우 현재 계획대로 문자열 스위치를 구현할 수 없습니다.
Dimitris Andreou

1
@DimitrisAndreou 예, 이제 Strings로 전환 할 수 있습니다. : D (몇 년 동안 : P)
J. Doe

-11

32 비트 아키텍처에서 long은 두 단어로 표시됩니다 . 이제 불충분 한 동기화로 인해 switch 문을 실행하면 한 쓰기에서 높은 32 비트가, 다른 쓰기에서 32 비트가 낮은 long을 관찰 할 수 있습니다. .... 어디를 아는 사람에게 가려고 할 수 있습니다! 기본적으로 어딘가에 무작위로. 두 쓰기가 모두 switch 문에 대해 유효한 경우를 나타내더라도, 그들의 재미있는 조합은 아마도 첫 번째도 두 번째로도 이어지지 않을 것입니다. 또는 극도로 더 나쁘면 다른 유효하지만 관련없는 경우로 이어질 수 있습니다!

적어도 int (또는 그보다 작은 유형)를 사용하면 아무리 심하게 엉망이 되더라도 switch 문은 적어도 "공기에서 벗어난"값 대신 누군가가 실제로 쓴 값을 읽습니다 .

물론 실제 이유는 모르겠지만 (15 년이 넘었고 그렇게 오랫동안주의를 기울이지 않았습니다!) 그러한 구조가 얼마나 안전하지 않고 예측할 수 없는지 알고 있다면 동의 할 것입니다. 이것은 확실히 아주 좋은 이유 하지에 지금까지 정수 (Long) 스위치 (그리고 한 -pun intended-이 32 비트 시스템 일 것입니다,이 이유는 유효합니다)가 있습니다.


1
나는 이것이 뒤 따르지 않는다고 생각합니다. 스위치가 켜진 값은 레지스터 나 스택에 계산 및 저장되어야합니다. 해당 값이 여러 스레드에서 액세스 한 데이터를 기반으로 계산되는 경우이 계산 은 결과의 너비에 관계없이 스레드로부터 안전해야합니다. 그러나 그 결과가 레지스터 나 스택에 있으면 스위칭 스레드에 의해서만 액세스되고 안전합니다.
Neil Coffey

Neil, 당신의 주장은 매우 혼란 스럽습니다. "하지만 그 결과가 레지스터 나 스택에 있으면 스위칭 스레드에 의해서만 액세스되고 안전합니다." 물론, 그 값을 사용하는 것은 스레드로부터 안전합니다! 하지만 내 요점은 사용자 코드의 동기화 버그로 인해 그 값이 _ 이미 _ 잘못 될 수 있다는 것 입니다. 스레드로부터 안전하게 잘못된 값을 사용하는 것은 유용하지 않습니다. :)이 문제는 절대로 제거 할 수 없습니다. 버그가있는 동시 코드는 이미 "공기 부족"/ 잘못된 긴 값을 생성했을 수 있으며, 나중에 스위치에서 사용할 수 있습니다. 아무도 지정하지 않은 케이스 주소로 전환 합니다 .
Dimitris Andreou

1
디미트리 스, 아마도 당신의 주장에 뭔가 이해가 안 돼요. 켜진 값은 사용자 코드의 동기화 버그로 인해 실제로 잘못되었을 수 있습니다. 그러나 나는 다른 경우보다 이것을 더 가능성있게 만드는 switch 문에 내재 된 어떤 것이 있다고 생각하지 않습니다. 그리고 최선을 다해 생각하면 메모리에 대한 긴 읽기 / 쓰기의 hi / low 단어의 비원 자성이 실제로 문제라고 생각하지 않습니다. (다른 방식으로 생각하기 : 동일한 주장에 근거하여 long에 대한 if 비교가 허용되지 않는다고 결정할 수 있습니다.)
Neil Coffey

원자 쓰기가 보장되지 않는 두 단어로 오랫동안 표현되는 잠재적 인 문제는 일반적인 문제이지만 스위치의 경우 훨씬 더 심각한 위험이 될 수 있습니다. 이는 주소의 절반이 한 사람에게서, 절반이 다른 사람에게서 온 메시지와 함께 봉투를 보내는 것과 같습니다. 최종 주소는 유효 할 수 있으며 봉투를 받고 그에 따라 행동 할 완전히 임의의 챕터에 해당합니다. 쓰레기를 읽고 쓰레기를 생성하는 것은 (잘못된 부울과 같은) 한 가지이지만 쓰레기를 읽고 무작위로 점프하는 것은 나에게 좀 더 위험한 것처럼 들립니다.
Dimitris Andreou

7
나는 이것이 오래되고 그것에 대해 논평하는 것이 일종의 논쟁이라는 것을 알고 있지만 나는 당신의 주장도 적용 if되고 그 결과는 나쁠 것임을 강조하고 싶습니다 . 잘못된 결과 ~> 잘못된 가지가 취했습니다. 긴 만들기 if- else- if대신 체인은 switch실제로 정확히 같은 결과로 이어질 것입니다.
Nicolai Parlog
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.