Javaに `void`メソッドがあるのはなぜですか?


51

Javaにvoidメソッドが必要なのはなぜですか?参照

voidと宣言されたメソッドは値を返しません。

私の考えている限り、のすべての使用はvoid、ステータスフラグ、呼び出されているオブジェクト、またはを返すことにより、より適切に機能しますnull

これにより、すべての呼び出しが割り当て可能なステートメントになり、ビルダーパターンとメソッドチェーンが容易になります。通常、効果のためにのみ呼び出されるメソッドは、ブールSuccess型またはジェネリック型を返すか、失敗すると例外をスローします。


そのため、サブルーチンを記述するために特別な構文は必要ありません。関数が使用するものと同じものを使用できます。
candied_orange

回答:


158

「この機能は成功または失敗する可能性があり、違いを認識できるほど十分に自己認識している」と「この機能の効果に関するフィードバックがない」の間にaaの違いがあるためです。なしではvoid、成功コードを無限にチェックし、実際には何もしていなくても、堅牢なソフトウェアを書いていると信じます。


10
しかし、成功したか失敗したかは、フラグを返すのではなく、例外をスローするかしないかで表現するものです。また、戻ることvoidは、メソッドまたは関数が適切にスローするのに十分な自己認識であるかどうかについては何も言いません。
フォルカーシーゲル

12
@VolkerSiegel:答えのコンテキストは質問です。OPは、voidが使用されるすべての場合に、関数は代わりに失敗の成功を示すステータスフラグを返すことを提案しました。そのコンテキストでは、voidを返すことは、実際、関数には文字通り何も返すものがないと言っています。そのような関数に常に0を返して成功を示すと、関数のユーザーは、実際には成功または失敗に関係なく、戻り値が常に0であるときにエラーチェックを行っているという誤った信頼を得ることができます。
-slebetman

19
@VolkerSiegel例外が物事を行う正しい方法ではない状況が数多くあります。実際、例外が間違っているよりも正しいことはまれだと言います。例外とは、説明が必要な恐ろしいことが起こったことを意味します。予想される障害のケースでは、例外を使用しないでください。
ゲイブSechan

35
@GabeSechanいいえ、メソッドがその契約を履行できない場合、例外をスローする必要があります。メソッドがnull以外の参照を必要とするが、それを取得する場合、予期される失敗であり、スローする必要があります。
アンディ

5
それを修正するための多くの代替構文があります。彼らがこの(厄介な)ソリューションを選んだのは、Cが採用しているからです。
マルコヴァンデフォールト

95
  1. Cにはvoid型があり、JavaはC言語ファミリの多くの規則に従うように設計されているためです。
  2. 値を返したくない関数がたくさんあります。Successとにかく「ジェネリック型」で何をするつもりですか?実際、成功を示す戻り値はCよりもJavaの方が重要です。Javaには失敗を示す例外があり、Cにはないためです。

8
>「とにかく「一般的な成功タイプ」で何をするつもりですか?」—ジェネリックコードを記述する場合、単一の値型(Unit type btwと呼ばれます)は、「単に戻る」が特別な何も返さない関数の特殊なケースを排除するため、非常に便利です。しかし、Javaが最初に作成されたときは、型システムが(表現型パラメーターなしで)表現力が低いため、実際的な違いはあまりありませんでした。そして今、変更するには遅すぎます。より現代的な言語は、実際にはvoid "type"(実際には型ではなく、メソッドの特別なマーカーである)を避け、代わりにUnit型を使用します。
セージボルシュ

9
@SargeBorsch JavaのVoid型はUnit型として機能しますが(たとえばGenericsの場合)、悲しいことに、それとは異なりますvoid(サイドノート:前のバージョンで台無しにした型を修正するために新しい型を発明するたびに、かわいい子猫が死にます)。ユニットのタイプに慣れていない人は、これがまともな紹介です:en.wikipedia.org/wiki/Unit_type
Ogre Psalm33

1
@ OgrePsalm33は実際にはUnit型としては機能しません(少なくとも実用的な方法では、Void戻り型を持つメソッドから戻るために「return null;」を記述する必要があり、AFAIKコンパイラはVoid参照用にスタック上のスペースを割り当てます、これらの値を読み取ることは無意味であるという事実を利用せずに)、「適切な」ユニットタイプがより適切である場合に使用するための単なる規則です。
セージボルシュ

3
@immibisというのは、定義によるユニットタイプは正確に1つの値を持つ必要があり、Voidには値がないためです。はい、使用nullすることは可能です(実際、これが唯一の選択肢です)が、nullは特別なものです。Javaの参照型の値はnullになる可能性があります(これは言語設計の別の失敗です)。また、前述したように、マークのVoid代わりに戻り値の型を使用している場合void、Javaコンパイラはあなたの友人ではありません。
セージボルシュ

5
@SargeBorsch Voidの値は1つだけですnullnullほとんどのタイプのメンバーであるという事実Voidは、ユニットタイプであるかどうかとは無関係です。
user253751

65

オリジナルの言語が持っている理由voidで好きなのでタイプがありC、言語のクリエイターが不必要で、言語の構文を複雑にしたくなかった手順 sおよび機能パスカルがやったの方法。

それが元々の理由でした。

あなたの提案:

ステータスフラグを返す

それはノーです。ステータスフラグは使用しません。問題が発生した場合は、例外を介して報告します。

呼び出されるオブジェクト

流fluentなスタイルの呼び出しは最近の開発です。今日流に非常に喜んで使用し、それをサポートしないインターフェースを使用しなければならない場合に目を転がすプログラマーの多くは、Javaが作成されたときにさえ生まれていませんでした。

nullを返す

実際には何も返さないのに、メソッドが何かを返すように宣言しなければならないので、それが何をしているのかを理解しようとするインターフェースを見ている人にとっては非常に混乱するでしょう。人々は必然的に「戻り値なし」を意味する、そうでなければ役に立たないクラスを発明するので、返すものを持たないすべての関数はそのようなクラスへのnull参照を返すことができます。それは不格好だ。幸いなことに、これには解決策がありvoidます。そして、それがあなたの質問に対する答えです。


3
「元の理由...」のソースを提供してください。私の知る限り、本当の理由は、Cがポータブルアセンブラーとして設計されているためです。
トールビョールンラヴンアンデルセン

6
@ThorbjørnRavnAndersenは、実際には、Javaの構文がCの構文から派生しているという主張のソースを提供するように私に求めているのですか?
マイクナキス

3
@ThorbjørnRavnAndersenああ、わかりました、私は誤解しました。したがって、Javaについてではなく、Cについての私の主張のソースが必要です。さて、申し訳ありませんが、その原因はありません。しかし、それはかなり明白だと思います。(1987年にCに切り替えたとき、私はパスカルでプログラムしていました。私の良さ、それは30年前です。)
マイクナキス

6
明らかではありません。Cは、パスカルとほぼ同じ時期に、Cの存在すら知らなかった人々によって開発されました。仮定を事実として述べないでください。
するThorbjörnRavnアンデルセン

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
太字の質問に対する正しい答えは、「ソートされた配列」です。
ブライアンベッチャー

2
@BryanBoettcher:残りを読んでいませんでしたか?
Mehrdad

1
@MichaelKjörling:これは、このようなエラーを防ぐためのJava言語の基本的なプロパティです。つまり、returnステートメントを忘れた場合に「未定義の動作」が発生しないようにします。代わりに、間違いを知らせるコンパイラエラーが表示されます。暗黙の挿入は、return null;「未定義の動作」よりも優れていますが、それほど多くはありません。これは、戻り値の型に意味がない場合にのみ役立ちますが、コンパイラは、戻り値が意味を持たない場合、どこから結論を導き出しvoidますか?
ホルガー

2
@MichaelKjörling:「return本当に値が追加されない場合は...」と言ったように、void型がなければ、戻り値が値を追加しないというコンパイラーの指標はありません。実際は逆です。最初の前提は、戻り値の型を宣言するメソッドreturnがその型の有用なものを必要としているということです。また、null値を持たないプリミティブ型についてはまだ説明していません。したがって、コンパイラによって注入されるデフォルト値は、潜在的に有用な戻り値の範囲と競合します。
ホルガー

7

boolean常にtrueあなたが提案するものと等しいa を返すことは、無意味であるだけでなく(戻り値に情報がない)、実際には誤解を招く可能性があります。ほとんどの場合、実際に利用可能な情報だけを運ぶ戻り値の型を使用するのが最善です。そのため、40億の可能な値を返すのではなく、Java booleantrue/を使用します。同様に、可能な値が1つしかない場合に「a」を2つの値で返す(「一般的な成功」)と誤解を招く可能性があります。falseintboolean

また、不必要なパフォーマンスのオーバーヘッドが追加されます。

メソッドがその副作用のみに使用される場合、返すものは何もなく、戻り値の型voidはそれを正確に反映します。潜在的なまれなエラーは、例外を介して通知できます。

改善できることの1つはvoid、Scalaのような実際の型を作成することUnitです。これにより、ジェネリックの処理などのいくつかの問題が解決されます。


楽しい事実は:List.add常に返すんtrueが、それはより広範な契約と互換性があるためだCollection.addそう、Set.add返すことがありtruefalse
ホルガー

4

Javaは比較的古い言語です。1995年(作成時)およびその後まもなく、プログラマーは、プロセスがプロセッサの制御にかかる時間とメモリの消費を非常に心配していました。voidを返すと、スタックに戻り値を置く必要がなくなり、その後削除する必要がないため、関数呼び出しから数クロックサイクルとメモリ消費が少し削減されます。

効率的なコードでは、決して使用しないものは返されません。そのため、無意味な戻り値を持つものにvoidを挿入することは、成功値を返すよりもはるかに良い方法です。


14
Javaの最初の実装が遅いことで有名なため、速度を非常に心配していたプログラマーは、最近ではJavaを使用しません。非常に遅いので、現在それを使っていない多くの人々は、Javaは太っていて遅いという同義語であるという印象をまだ受けています。
セージボルシュ

8
@SargeBorschは、20年前の古いプログラミングのジョークを思い出させます。"コンコン。" 「誰がいるの?」... ... ... ...非常に長い休止... ... ...の"Java"
ダン・ニーリー

4
@DanNeelyとしばらくしてから、AI駆動の車がブレーキをかけようともせずに全速力で壁に衝突します。Javaで書かれています。だから、Java は今ブレーキをかけません!(それはロシア語のしゃれだった、それを英語に非常にうまく翻訳できない)
セージボルシュ

2
@SargeBorsch翻訳でニュアンスが失われたとしても、英語のしゃれとして機能します。そして、しゃれを翻訳することはおそらく詩よりも難しいです。
ダン・ニーリー

3
優れたプログラマーは、メモリのパフォーマンスと消費に依然として関心を持っています。そのため、今日でも不要なゴミを返すように人々に要求しています。
Sklivvz

2

私は、2番目のオプション(return this)がの代わりにアプローチであると示唆する引数を読みましたvoid。これはかなり良い考えですが、Javaが作成された時点ではビルダースタイルのアプローチは一般的ではありませんでした。それが今と同じくらい当時に人気があった場合、それは取られたアプローチであったかもしれません。返品nullは非常に悪いアイデアです。私nullは言語でさえ全くなかったらよかったのに。

問題は、メソッドがそれ自身の型のインスタンスを返す場合、それが新しいオブジェクトであるか同じオブジェクトであるかが明確ではないということです。多くの場合、それは問題ではありません(またはすべきではありません)が、問題になる場合もあります。thisvoidメソッドを暗黙的に返すように言語を変更できると思います。現時点で私が考えることができる唯一の問題は、メソッドが後で同じ型の新しいオブジェクトを返すように変更された場合、コンパイルの警告はないことですが、それは大したことではないかもしれません。現在の型システムは、これらのタイプの変更を気にしません。これが継承/インターフェースとどのように相互作用するかについては、ある程度の検討が必要ですが、ビルダースタイルのない古いAPIを、あたかもそうであるかのように簡単に呼び出すことができます。


2
@Cody良い点、これは静的メソッドには適用されません。
ジミージェームズ

14
@ marisbest2どの引数?
8bittree

3
さて、null言語の一部ではない場合、人々は「この引数/戻り値を無視してください、賢明な値は含まれていません」という意味のあらゆる種類のセンチネル値を使用します。問題nullはそれ自体ではなく、間違って使用される傾向があるということだけです。私は、標準化されている場合、この問題が誇張だろうと賭けをいただきたいnull各実装は黙っなど、使用状況を無視して、またはその代わりスタンダールヌルポインタ例外の特別な例外を投げるように異なる振る舞いますカスタムソリューションの無数に置き換えられます
cmaster

2
@cmasterの明らかな代替nullは、適切なオプション型です(MaybeHaskellなど)。Javaでのnullの問題は、実際に値がnull可能かどうかをすぐに判断するための適切な方法がないことです。これは、不必要な防御的プログラミング(無意味な場所でヌルをチェックし、それによってコード内のうんちの割合を増やす)と、生産中の偶発的なNPE(必要な場所を確認するのを忘れた場合)の両方につながります。ええ、それは注釈によって部分的に解決されますが、オプションであり、常にチェックされるわけではありません。したがって、サードパーティのコードとの境界であなたを救うことはありません。
セージボルシュ

2
@SargeBorsch私はそれに同意します:-)私の反対は、「この値を無視してください」を表現する標準的な方法のない言語に対するものです。nullこれに対しては正常に動作しますが(fine = simple)、ソリッドセマンティクスを備えた標準化されたオプション値は、間違いなく別の素晴らしいオプションです(fine = safe)。
cmaster

2

別の側面:

Javaは非常に厳密な機能を持つ静的言語です。これは、他の言語(c / f Ruby、Lispなど)で非常にオープンまたはダイナミックになる多くのものが厳密に決定されることを意味します。

これは一般的な設計上の決定です。「理由」に答えるのは難しいです(まあ、言語の設計者はそれが良いと思ったからです!)「何のために」は非常に明確です:それはコンパイラが多くのエラーを検出することを可能にします。それは一般にどんな言語にとってもかなり良い機能です。第二に、言語について比較的簡単に推論することができます。たとえば、Java言語(のサブセット)で正式な証明を作成するのは比較的簡単です。比較として、Rubyなどの動的言語では事実上不可能です。

この考え方は、言語に浸透します。たとえば、メソッドがスローできる例外の強制的な宣言、曖昧な多重継承を避けるためのinterfacevs の個別のタイプなどclassです。それが何であるか(コンパイル時のエラー処理に重点を置いた静的な命令型OOPの実世界の言語)については、実際には非常にエレガントで強力です。これらは、これらの問題の一部を調査するために意図的に作られた理論的(科学的)言語に近づきます(他の実際の言語よりも)

そう。厳密なvoid型を持つことは明確なメッセージです。このメソッドは何も返しません、期間。それが現実さ。常に何かを返すように強制で置き換えると、はるかに動的な振る舞いになります(すべての defが常に明示的または暗黙的な戻り値を持つRubyのように)。これは、証明可能性と推論に悪いでしょう。またはここで他のメカニズムを使用して大規模に膨らませます。

(そして、NB、ルビー(例えば)のハンドルは、この異なっており、その解決策はまだ正確として受け入れ、それは完全に異なる哲学を持っているので、Javaのように。入れながら、例えば、それは完全に窓の外に証明可能性と合理性をスローに焦点を言語の非常に高い表現力。)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.