Java에 왜 'void'메소드가 있습니까?


52

Java에 void메소드 가 필요한 이유는 무엇입니까? 참고 :

void로 선언 된 메서드는 값을 반환하지 않습니다.

내가 생각할 수 void있는 한, 상태 플래그, 호출되는 객체 또는를 반환하면 모든 사용 이 더 잘 제공됩니다 null.

이것은 모든 호출을 지정 가능한 명령문으로 만들고 빌더 패턴과 메소드 체인을 용이하게합니다. 효과에 대해서만 호출되는 메소드는 일반적으로 부울 또는 일반 Success유형을 리턴하거나 실패시 예외를 발생시킵니다.


따라서 서브 루틴을 작성하기 위해 특별한 구문이 필요하지 않습니다. 우리는 동일한 기능을 사용할 수 있습니다.
candied_orange

답변:


159

"이 기능은 성공 또는 실패 할 수 있으며 차이점을 알 수있을만큼 충분히 자각합니다"와 "이 기능의 효과에 대한 피드백이 없습니다"라는 차이점이 있기 때문입니다. 없이는 void성공 코드를 끝없이 확인하고 실제로 아무 것도 수행하지 않을 때 강력한 소프트웨어를 작성하고 있다고 생각합니다.


10
그러나 성공 또는 실패 여부는 플래그를 반환하지 않고 예외를 던지거나 던지지 않고 표현하는 것입니다. 그리고 반환 void은 메소드 또는 함수가 적절하게 던질 정도로 충분히 자각하는지 여부에 대해 아무 말도하지 않습니다.
Volker Siegel

12
@ VolkerSiegel : 대답의 맥락은 질문입니다. OP는 void가 사용되는 모든 경우에 함수가 대신 실패 성공을 나타내는 상태 플래그를 반환해야한다고 제안했습니다. 그 맥락에서 void DOES를 반환하는 것은 실제로 함수가 문자 적으로 반환 할 것이 없다고 말합니다. 이러한 함수가 항상 0을 반환하여 성공을 나타내도록하면 함수의 성공 여부에 관계없이 실제로 반환 값이 0 일 때 오류를 확인하고 있다는 잘못된 확신을 사용자에게 제공합니다.
slebetman

19
@VolkerSiegel 예외가 올바른 작업 방법이 아닌 많은 상황이 있습니다. 사실 나는 예외보다 옳은 것이 드문 것이라고 말하고 싶습니다. 예외는 끔찍한 일이 발생해야한다는 것을 의미합니다. 예상되는 실패 사례는 예외를 사용해서는 안됩니다.
Gabe Sechan

35
@GabeSechan 아니오, 메소드가 계약을 이행 할 수없는 경우 예외가 발생해야합니다. 메소드에 널이 아닌 참조가 필요하지만 참조가 있으면 예상되는 실패이므로 예외가 발생합니다.
Andy

5
이를 해결하기위한 많은 대체 구문이 있습니다. 그들이 (어색한) 해결책을 선택한 이유는 C가 그것을 사용하기 때문입니다.
Marco van de Voort

96
  1. C에는 void유형이 있고 Java는 C 언어 제품군의 많은 규칙을 따르도록 설계 되었기 때문 입니다.
  2. 값을 반환하지 않으려는 많은 기능이 있습니다. Success어쨌든 " 일반 유형"으로 무엇을 하시겠습니까? 실제로 Java는 실패를 나타내는 예외가 있고 C는 그렇지 않기 때문에 성공을 나타내는 반환 값은 C보다 Java에서 훨씬 덜 중요합니다.

8
> "어쨌든"일반적인 성공 유형 "으로 무엇을 하시겠습니까?" — 일반 코드를 작성할 때 단일 값 유형 (단위 유형 btw라고 함)은 "반환"하지만 특별한 것은 반환하지 않는 특수한 경우를 제거하므로 매우 유용합니다. 그러나 Java가 처음 만들어 졌을 때 표현 유형 시스템이 적기 때문에 (유형 매개 변수 없음) 실질적인 차이는별로 없었습니다. 그리고 지금 변경하기에는 너무 늦었습니다. 보다 현대적인 언어는 실제로 void "type"을 피하고 (실제로는 유형이 아니라 메서드의 특수 마커 일뿐) Unit 유형을 대신 사용합니다.
Sarge Borsch

9
@SargeBorsch Java의 Void유형은 단위 유형 (예 : Generics) 의 역할을하지만 슬프게도 다릅니다 void(참고 : 이전 버전에서 엉망인 유형을 수정하기 위해 새 유형을 발명 할 때마다 귀여워 새끼 고양이가 죽습니다). 누구든지 유닛 유형에 익숙하지 않다면, 이것은 괜찮은 소개입니다. en.wikipedia.org/wiki/Unit_type
오우거 시편 33

1
@ OgrePsalm33 실제로 단위 유형으로 작동하지는 않습니다 (적어도 실질적인 방법은- "반환 null"을 작성해야 Void 반환 유형이있는 메서드에서 반환해야하며 AFAIK 컴파일러는 Void 참조를 위해 스택에 공간을 할당합니다) , 이러한 값을 읽는 것이 의미가 없다는 사실을 이용하지 않음) "적절한"단위 유형이 더 적절한 위치에서 사용하는 것은 단지 관례 일뿐입니다.
Sarge Borsch

3
정의에 의한 단위 유형은 정확히 하나의 값을 가져야하고 Void에는 값이 없기 때문에 @immibis 예, 사용할 수는 있지만 null(실제로는 이것이 유일한 선택입니다) null은 특별한 것이며 Java의 참조 유형 값은 null 일 수 있습니다 (언어 디자인의 또 다른 실수입니다). 그리고 앞에서 언급했듯이 mark Void대신 return 유형을 사용하는 void경우 Java 컴파일러는 친구가 아닙니다.
Sarge Borsch

5
@SargeBorsch Void의 값은 정확히 하나입니다 null. null대부분의 유형의 구성원 이라는 사실 Void은 단위 유형 인지 여부와 관련이 없습니다 .
user253751

65

원래 언어가 왜 이유 void등에 있기 때문에 유형입니다 C, 언어의 창조자가 불필요과 언어의 구문을 복잡하게하고 싶지 않았다 절차 의 및 기능 파스칼이 한의 길을.

그게 원래의 이유였습니다.

당신의 제안 :

상태 플래그를 반환

그건 아니에요 상태 플래그는 사용하지 않습니다. 문제가 발생하면 예외를 통해보고합니다.

호출되는 객체

유창한 스타일의 호출이 최근 개발되었습니다. 오늘날 매우 유창하게 유창하게 사용하고 있고 지원하지 않는 인터페이스를 사용해야하는 경우 Java를 만들 때조차 태어나지 않은 많은 프로그래머들이 눈을 감고 있습니다.

null을 돌려주는

그렇게하면 실제로 무언가를 반환하지 않을 때 메소드가 무언가를 리턴하는 것으로 선언해야하므로, 그것이 무엇을하는지 알아 내려고하는 인터페이스를보고있는 사람에게는 매우 혼란 스러울 것입니다. 사람들은 필연적으로 "반환 값 없음"을 의미하는 쓸모없는 클래스를 발명하여 반환 할 항목이없는 모든 함수가 해당 클래스에 대한 null 참조를 반환 할 수 있습니다. 그것은 어색 할 것입니다. 운 좋게도 이에 대한 해결책이 void있습니다. 이것이 귀하의 질문에 대한 답변입니다.


3
"원래 이유 ..."에 대한 소스를 제공하십시오. 내 지식으로는 실제 이유는 C가 휴대용 어셈블러로 설계 되었기 때문입니다.
Thorbjørn Ravn Andersen

6
@ ThorbjørnRavnAndersen 실제로 Java의 구문이 C 구문에서 파생되었다는 주장에 대한 소스를 제공하도록 요청하고 있습니까?
Mike Nakis

3
@ ThorbjørnRavnAndersen 오, 나는 오해를 본다. 따라서 Java가 아닌 C에 대한 나의 주장에 대한 출처를 원합니다. 알겠습니다. 죄송합니다. 그러나 나는 그것이 분명하다고 생각합니다. (저는 C로 전환했을 때 1987 년 파스칼에서 프로그램을 했어요. 30 년 전입니다.)
Mike Nakis

6
분명하지 않습니다. C는 존재 여부조차 알지 못하는 사람들이 파스칼과 거의 동시에 개발했습니다. 가정을 사실로 진술하지 마십시오.
Thorbjørn Ravn Andersen

12
진짜 원래 이유는 기본 C 함수가 반환에 의해이었다 int, 그래서 키워드가 '더 리턴 타입'을 나타 내기 위해 K & R에 이후 추가되었습니다.
user207421

20

와 같은 일부 메소드 System.out.println는 유용한 것을 반환하지 않지만이 부작용을 위해 순수하게 호출됩니다. void유용한 값이 리턴되지 않는 컴파일러 및 코드 리더에게 유용한 표시기입니다.

null대신에 반환 한다는 것은 이 값을 무엇이든 사용하는 순간을 void얻는다 는 것을 의미합니다 NullPointerException. 따라서 런타임 오류에 대해 컴파일 시간 오류를 교환합니다. 또한 반환 유형을로 정의해야 Object하므로 오해의 소지가 있고 혼란 스러울 수 있습니다. (그리고 체인은 여전히 ​​작동하지 않습니다.)

상태 코드는 일반적으로 오류 조건을 나타내는 데 사용되지만 Java에는이 목적에 대한 예외가 있습니다.

this정적 메소드에서 리턴 할 수 없습니다.

일반 Success객체를 반환하는 것은 유용한 목적이 없습니다.


1
가장 단순하고 간결한 답변 인 귀하에게 전적으로 동의하십시오.
webo80

11

한 가지 이유가 될 수 있다는 오해의 소지가 이제까지 말 이외의 아무것도 반환하기 null. 예:

무엇을 Arrays.sort(a)반환 해야 합니까?

a호출이 연결될 수 있도록 리턴되어야 한다고 주장하는 경우 (질문에서 판단한 응답 인 것 같음) 리턴 값이 원래 오브젝트 의 사본 인지 또는 원래 오브젝트 자체 인지 명확하지 않습니다. . 둘 다 가능합니다. 그렇습니다. 문서에 넣을 수는 있지만 애매 모호함을 만들어서는 안됩니다.

반면에, 그것이 null반환되어야 한다고 주장한다면 , 그것은 반환 값이 어떤 정보를 호출자에게 제공 할 수 있는지, 그리고 return null정보를 전달하지 않을 때 프로그래머가 왜 작성해야하는지에 대한 질문을 제기 합니다.

그리고 당신이 완전히 터무니없는 것을 반환하면 (길이와 같은 a) 반환 값을 사용하는 것이 실제로 혼란 스럽습니다 . int len = Arrays.sort(a)대신 더 혼란 스럽습니다 int len = A.length!


1
모든 공정성에서 프로그래머는 반드시 작성해야 할 필요는 없습니다 return null;. JVM은 명시 적 return또는 throw명령문 이외의 방법으로 제어가 함수의 끝에서 벗어나면 null암시 적으로 호출자에게 리턴되도록 명령 할 수 있습니다. IIRC C는 그 경우에 반환 값이 정의되어 있지 않다는 점을 제외하고 그렇게합니다.
CVn

2
굵게 표시된 질문에 대한 정답은 "정렬 된 배열"입니다.
Bryan Boettcher

2
@BryanBoettcher : 나머지는 읽지 않았습니까?
Mehrdad

1
@Michael Kjörling : 이러한 오류를 방지하는 것은 Java 언어의 기본 속성입니다. 즉, return문장 을 잊어 버린 경우 "정의되지 않은 동작"이 발생하지 않습니다 . 대신 실수에 대해 알려주는 컴파일러 오류가 발생합니다. 암시 적 삽입은 return null;"정의되지 않은 동작"보다 낫지 만 그리 많지는 않습니다. 반환 유형에 의미가없는 경우에만 유용하지만 컴파일러는 반환 값에 의미가 없다는 결론을 어디에서 얻 void습니까?
Holger

2
@ MichaelKjörling :“ return정말로 값을 추가하지 않으면…”라고 말했듯이, 컴파일러가 void타입 이 없다면 리턴 값이 값을 추가하지 않는다는 표시기가 없습니다 . 실제로 반대입니다. 첫 번째 가정은 반환 유형을 선언하는 메서드 return가 해당 유형에 유용한 것을 원한다는 것입니다. 그리고 우리는 아직 null값 이없는 기본 유형에 대해 이야기하지 않았 으므로 컴파일러가 주입 한 기본값은 잠재적으로 유용한 반환 값의 범위와 충돌합니다.
Holger

7

boolean항상 true제안한 것과 동일한 a 를 반환하는 것은 의미가 없으며 (반환 값에는 정보가 없음) 실제로 잘못 될 수 있습니다. 대부분의 시간, 그것은 실제로 가능한만큼 많은 정보를 전달 반환 형식을 사용하는 것이 가장 좋습니다 - 자바에서 당신이 그 이유는 boolean대한 true/ false오히려 반환보다 int40 억 개 가능한 값으로. 마찬가지로 boolean하나의 가능한 값 ( "일반적인 성공")이있는 두 개의 가능한 값 으로 a 를 반환하면 오해의 소지가 있습니다.

또한 불필요한 성능 오버 헤드가 추가됩니다.

메소드가 부작용에 대해서만 사용되는 경우 리턴 할 항목이 없으며 리턴 유형에 void정확하게 반영됩니다. 예외를 통해 잠재적 인 드문 오류를 알릴 수 있습니다.

개선 될 수있는 한 가지는 voidScala와 같은 실제 유형을 만드는 것 Unit입니다. 이렇게하면 제네릭 처리와 같은 일부 문제가 해결됩니다.


재미있는 사실 : List.add항상 반환 true하지만, 더 광범위한 계약과 호환 Collection.add되기 때문에 또는 Set.add반환 할 수 있습니다 . truefalse
Holger

4

Java는 비교적 오래된 언어입니다. 그리고 1995 년 (생성 당시) 프로그래머들은 프로세스가 프로세서를 제어하는 ​​시간과 메모리 소비에 대해 매우 염려했습니다. void를 반환하면 스택에 반환 값을 넣을 필요가없고 나중에 제거 할 필요가 없기 때문에 함수 호출에서 약간의 클럭주기와 약간의 메모리 소비가 제거됩니다.

효율적인 코드는 결코 사용하지 않는 것을 돌려주지 않으므로 의미없는 리턴 값을 가진 것에 void를 두는 것이 성공 값을 리턴하는 것보다 훨씬 더 나은 방법입니다.


14
속도에 관심이 많은 프로그래머는 요즘 자바를 사용하지 않을 것이다. 왜냐하면 자바의 첫 구현은 느리게 진행 되었기 때문이다. 현재 Java를 사용하지 않는 많은 사람들이 Java가 뚱뚱하고 느리다는 동의어에 여전히 빠져 있습니다.
Sarge Borsch

8
@SargeBorsch는 20 년 전의 오래된 프로그래밍 농담을 상기시킵니다. "똑 똑." "누가 있습니까?" ... ... ... ... 매우 멈춤 ... ... ... "자바"
Dan Neely

4
@DanNeely 그리고 얼마 후, 인공 지능으로 움직이는 자동차는 브레이크를 사용하지 않고 전속력으로 벽에서 충돌합니다. Java로 작성되었습니다. 따라서 Java 는 지금 제동하지 않습니다! (러시아어 말장난, 영어로 잘 번역 할 수 없습니다)
Sarge Borsch

2
@SargeBorsch 번역에서 뉘앙스를 잃어버린 경우에도 영어 말장난으로 작동합니다. 그리고 말장난 번역은 아마도 시보 다 더 어려울 것입니다.
Dan Neely

3
좋은 프로그래머는 여전히 메모리의 성능과 소비에 관심이 있으며, 오늘날에도 사람들에게 쓰레기를 반환하도록 불필요하게 요구합니다.
Sklivvz

2

나는 두 번째 옵션 (return this)이 대신 접근해야 한다는 주장을 읽었습니다 void. 이것은 좋은 아이디어이지만 Java가 작성 될 때 빌더 스타일 접근 방식은 인기가 없었습니다. 당시와 같이 인기가 높았다면 그 방법이 사용되었을 수 있습니다. 귀국 null은 정말 나쁜 아이디어 IMO입니다. 나는 null언어조차 전혀 없었 으면 좋겠다 .

문제는 이제 메소드가 자체 유형의 인스턴스를 리턴하는 경우 새 오브젝트인지 동일한 것인지 명확하지 않다는 것입니다. 종종 중요하지 않지만 다른 경우에는 중요하지 않습니다. thisvoid 메소드 에서 암시 적으로 리턴하도록 언어를 변경할 수 있다고 가정합니다 . 내가 생각할 수있는 유일한 문제는 나중에 메소드가 동일한 유형의 새 객체를 반환하도록 변경되면 컴파일 경고는 없지만 큰 문제는 아니라는 것입니다. 현재 유형 시스템은 현재 이러한 유형의 변경에 신경 쓰지 않습니다. 이것이 상속 / 인터페이스와 상호 작용하는 방법에는 약간의 고려가 필요하지만 빌더 스타일이없는 이전 API를 마치 마치 마치 쉽게 호출 할 수 있습니다.


2
@Cody 좋은 점, 이것은 정적 메소드에는 적용되지 않습니다.
JimmyJames

14
@ marisbest2 어떤 주장?
8bittree

3
글쎄요, null언어의 일부가 아니라면 사람들은 "이 인수 / 반환 값을 무시하십시오. 어떤 의미있는 값도 포함하지 않습니다"라는 의미의 모든 종류의 센티넬 값을 사용하고있을 것입니다. 문제 null는 그 자체가 아니라 잘못 사용되는 경향이 있다는 것입니다. 표준화 된 방식 null이 무수히 많은 맞춤형 솔루션으로 대체 될 경우에만이 문제가 과장 될 것입니다. 각 구현은 사용법을 자동으로 무시하거나 표준 널 포인터 예외 대신 특수 예외를 던지는 것과 같이 다르게 작동합니다.
cmaster

2
@cmaster의 확실한 대체 방법 null은 적절한 옵션 유형입니다 (예 : MaybeHaskell). Java에서 널 (null)의 문제점은 실제로 값을 널 (NULL)로 입력 할 수 있는지 여부를 즉시 결정할 수있는 방법이 없다는 것입니다. 불필요하게 방어적인 프로그래밍 (무의미한 곳에서는 null 확인, 코드에서 똥 비율 증가)과 실수로 프로덕션에서 NPE (필요한 곳을 확인하지 못한 경우)로 이어집니다. 예, 주석으로 부분적으로 해결되었지만 선택 사항이며 항상 확인되는 것은 아닙니다. 따라서 타사 코드가있는 경계에서 당신을 구하지는 않습니다.
Sarge Borsch

2
@SargeBorsch 나는 다음 사항에 동의한다 :-) 나의 반대는 "이 값을 무시하십시오"를 표현하는 표준적인 방법이없는 언어에 대한 것이다. null이것에 대해서는 잘 작동하지만 (고급 = 단순) 견고한 의미론을 가진 표준화 된 옵션 값은 또 다른 훌륭한 옵션입니다 (고정 = 안전).
cmaster

2

또 다른 측면 :

Java는 매우 엄격한 기능을 가진 정적 언어입니다. 이것은 다른 언어 (c / f Ruby, Lisp 등)에서 상당히 개방적이거나 역동적 인 많은 것들이 엄격하게 결정됨을 의미합니다.

이것은 일반적인 디자인 결정입니다. "왜"는 대답하기 어렵다. "무엇을위한 것"은 매우 분명합니다. 컴파일러가 많은 오류를 감지 할 수있게하는데 , 이는 일반적으로 모든 언어에 매우 유용한 기능입니다. 둘째로, 언어에 대해 추론하기가 비교적 쉽습니다. 예를 들어, 자바 언어에서 (정규화 된) 정확성을 증명하는 것은 비교적 쉽다. 이에 비해 Ruby 등의 동적 언어에서는 사실상 불가능합니다.

이 사고는, 예를 들어, 메소드가 던질 수있는 가능성이 예외의 강제 선언의 분리형, 언어를 침투 interface대는 class등 모호한 다중 상속을 방지하고. 그것이 무엇인지 (컴파일 타임 오류 처리에 중점을 둔 정적 명령형 OOP 실제 언어) 실제로는 매우 우아하고 강력합니다. 그들은 이론적 (과학) 언어에 더 가깝게 왔는데, 이는 이전에 다른 어떤 실제 언어보다 이러한 문제를 탐구하기 위해 의도적으로 만들어졌습니다.

그래서. 엄격한 void유형 을 갖는 것은 분명한 메시지입니다.이 메소드는 마침표를 반환하지 않습니다. 그것이 무엇입니까. 강제로 무언가를 항상 반환하도록 바꾸면 훨씬 더 역동적 인 행동으로 이어질 것입니다 (루비 에서처럼 모든 데프가 명시 적이거나 암시적인 반환 값을 갖는 루비처럼 ). 또는 다른 메커니즘을 사용하여 엄청난 팽창을 유발합니다.

(그리고 NB, 루비 (예를 들어) 다른이를 처리하고 그 해결책은 아직 정확히로 인정 , 자바 등이 완전히 다른 철학을 가지고 있기 때문에 퍼팅있다. 예를 들어이 창 밖으로 완전히도 낮게과 합리성을 던졌습니다 초점을 언어의 표현력이 매우 뛰어납니다.)

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