• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:java, c# 追加失敗時の処理)

java, c# 追加失敗時の処理

このQ&Aのポイント
  • キーの重複時の追加処理について、javaとc#の違いや利用方法を検討しています。
  • javaとc#での重複キーの追加処理の違いや利便性について議論しています。
  • コレクションクラスにおけるキーの重複時の追加処理について、javaとc#のメソッドの使い方や利用価値について考察しています。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.5

> しかし、javaのデフォルトのライブラリを使っていて驚いたことが、「例外のエラーメッセージとメソッ > ドのパラメータ名が一致しない」、「そのうえ、そんな値のパラメータを渡していない」、「そもそも、 > そんなパラメータ名の値を渡していない」ということです。 >  原因はおおよそ見当付いていますが…。 >  Addをそのまま使っていると、似たような混乱を生みかねないので、値を追加できなくて、”正しい(分 > かりやすい)”例外を出すためにTryAddを使おうという考えです。 なるほど、JDKのどのクラスのメソッドが該当するのか全く把握していませんが、 そんなのがあるんですね。 そういった正当な理由がある上で『あえて』捕捉するならば、パフォーマンス改善の 考え方も頷けますし、アリと思います。 が、きっとそれはライブラリなどのライブラリ・フレームワーク側が実装する方法であって、 それを利用して開発を行う側では、Add()、TryAdd()の利用用途が変わる場合もあると思いますよ。 (まあ、主にそれが実装スタイルの思想や要件によるでしょうけど)

koumei000
質問者

お礼

 遅くなりました。回答ありがとうございます。  (自作例外クラスがそこそこ改良できたので、リファクタリングに追われて、すっかり忘れていました)  そうですね。いろいろな使い方、考え方の人がいるのですから、それぞれのニーズに合ったクラス設計が大切ですよね。  お騒がせしました。この度はありがとうございました。

その他の回答 (4)

回答No.4

んと、恐らく思想によると思います。 私は 『意図して例外を発生させる』なら、try catchは使わない。 『意図していない時に例外を発生させる』なら、try catchを使う。 です。 上記思想の下に適切な命令方法を優先し、速度を最重要視することはしません。 例えば重複キーがないであろう前提、もしくは重複キーがある場合には 特別なエラーという挙動を考える時に、 try {  dictionary.Add(key, value); } catch (Exception e) {  throw new Exception("なんか固定のエラーメッセージ"); } みたいなことをしているならば、それはtry catchに頼るべきではなく、 ContainsKeyなどで検証します。(多少速度が遅かろうと関係ない) try catchは、想定外、他命令で捕捉不可能な場合のみ利用します。 if (dictionary.ContainsKey(key)) {  throw new Exception("なんか固定のエラーメッセージ"); } dictionary.Add(key, value); で、その流れの考えでいくと > if ( dictionary.TryAdd(key, value) == null ) >  throw new ~Exception(……); と、例外発生ではなく if ( dictionary.TryAdd(key, value) == null ) {  ~ なにか別な処理 ~ } 『なにか別な処理』が必要な場合にはこの記述でいいのではないでしょうか。 値が設定できなくて例外にするなら、TryAdd()をする必要ありませんよね。 いずれにしても、少なからず『Try』する必要がないロジックも存在します。 その時に『Try』するのは個人的にはナンセンスです。 C#で言ったら、絶対的にパースできると分かり切っているロジックに対しても いちいちint.TryParse()しているようなものなので。 速度ではなく、ロジックの見せ方と、例外の扱い方として。 色んな人のやり方があるわけですし、両方あっても別にいいのでは?

koumei000
質問者

お礼

 回答、ご指摘ありがとうございます。 > 色んな人のやり方があるわけですし、両方あっても別にいいのでは?  確かにその通りです。これは前述の通り納得・解決しました。  ちょっと、誤解がありそうなので補足。 > 『なにか別な処理』が必要な場合にはこの記述でいいのではないでしょうか。 > 値が設定できなくて例外にするなら、TryAdd()をする必要ありませんよね。  一般的にはその通りです。しかし、javaのデフォルトのライブラリを使っていて驚いたことが、「例外のエラーメッセージとメソッドのパラメータ名が一致しない」、「そのうえ、そんな値のパラメータを渡していない」、「そもそも、そんなパラメータ名の値を渡していない」ということです。  原因はおおよそ見当付いていますが…。  Addをそのまま使っていると、似たような混乱を生みかねないので、値を追加できなくて、”正しい(分かりやすい)”例外を出すためにTryAddを使おうという考えです。

回答No.3

> そのクラスでAddしたときに例外が出たときに、適切なエラーメッセージにならないことが多いので、 > TryAddを使うことが多いんですね。 >  try-catchならAddでもいいのですが、ちょとだけ行が増えるので敬遠気味です。 エラーメッセージなどの『例外ではない挙動』を必要とする処理をするならば try catchではなくContainsKey()などを利用すべきではないでしょうか。

koumei000
質問者

お礼

 再びの回答、ご指摘ありがとうございます。  確かに、 if ( dictionary.ContainsKey(key) )   throw new ~Exception(……); else Add(key, value);  などでも if ( dictionary.TryAdd(key, value) == null )   throw new ~Exception(……);  や、try-catchでAddを使うことの代用には動作的に十分だと思います。  ただし、これではContainsKeyと、Addで「一致するキーを探す」という処理を2回も行っています。  ご存知かと思いますが、たいていの場合、MapやDictionaryの「一致するキーを探す」処理が追加処理(時間)の大半を占めます(TreeMapなどで、回転を行う場合や、配列が一杯になって、コピーする場合もその限りではありませんが)。  そのため、if ContainsKey+Addの場合は2倍近い時間がかかり、わざわざ使おうという気がしません。  別にオーダーが変わっているわけではないので、if TryAddのコードの可読性が低いようならif ContainsKey+Addを使いますが、1行減&可読性はそんなに下がらないので後者の方が良いかなと。  さらに改善するならnullを static readonly Object Failed = null; (名前はKeyDuplicatedでもよい)  に変え、 if ( dictionary.TryAdd(key, value) == Failed )  とすれば十分、可読性は確保できると思います。

回答No.2

> それでもデフォルトで、一番使われそうなadd/Addメソッドがあまり使われないようなクラスというのはい > かがなものなのでしょうか? そんなことないと思いますけどね。 Add()は追加を前提とする場合の処理であって、TryAdd()は追加されない場面も少なからず存在します。 例えばAdd()で例外が発生する場合、この場合は、単純にコードが不正だから成り立つ事柄です。 これについては、『追加することを前提』としたコードを書いているわけですから、 例外が発生した方がベターであることは誰でもわかるでしょう。 それに対してTryAdd()でnullが返却される場合、別に不正でもなんでもないわけです。 コードでそういう動きが必要だからそうするわけですよね? (例えばある特定の条件化では既に事前にkey『ABC』が格納済みであり、それを何よりも優先 させることを前提で後続処理を行いたいなど) ↑ 個人的には、走行させるにも関わらず変化がないロジックを書くことは解析の手間上、好みませんが。 つまり、場面に応じてAdd()、TryAdd()を使い分けると思います。 場面を無視して常にTryAdd()を使用することは正直正しい選択とは思いません。 私ならむしろTryAdd()の方がほぼ利用しません。 (TryAdd()した結果を判定してどうのこうのしたい時くらいで、格納できなかった場合に 何もしないみたいなロジックは書かない。書いたら検証してる意味がない。) 何らかの潜在的な障害があった時、TryAdd()で書いてて、本来は値が書き換わってほしい、 もしくはそこで初めて値が入ると認識していた場合に誤動作を起こすわけですから、 そういう認識ならば、本来はAdd()で記述して例外が発生した方が正確でしょう。 だから、(2)があれば(1)は不要という結論には至りません。

koumei000
質問者

お礼

 回答ありがとうございます。  よくよく考えてみれば、長い間ライブラリ作りばっかりやってきたことが原因でしょうか?  終端部分であるアプリケーションのコードで使用されることより先に、自分が次(今)作るライブラリで使用することを想定して作って(質問して)いました。  そのため、他のクラスをDecoratorとして使うと、そのクラスでAddしたときに例外が出たときに、適切なエラーメッセージにならないことが多いので、TryAddを使うことが多いんですね。  try-catchならAddでもいいのですが、ちょとだけ行が増えるので敬遠気味です。  末端のアプリケーションなら、確かにAddの方が多いかもしれませんね。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

個人的には「キーの重複は『例外』なのか?」という疑問があるので, 今自分で作るなら (2) くらいかなぁ. ただ, これを全部作るとするともっとわかりやすい名前がほしい. 例えば, 「TryAdd」では (「try」とついている分だけ却って) 例外を送出するように感じるかもよ. ちなみに C++ の map::insert は (4)+α だったりする (「+α」は「既にあったかどうか」の情報も返すところ).

koumei000
質問者

お礼

 貴重なご意見ありがとうございます(ひょっとしたら久しぶりですかね)。  ちょっと誤解がありそうなので、補足しておきます。  Addは飽くまで「追加」で、Setを「関連付け(Associate)」としています。 > キーの重複は「例外」なのか  個人的な意見ですが、「追加」という操作に関しては間違いなく例外だと思います。  要素の個数はまったく増えませんから(イメージとしてはAddNew)。 > (「try」とついている分だけ却って)例外を送出するように感じる  ですが、これはc#の、  ・Dictionaryのboolean TryAdd(TKey key, out TValue)  ・int(Int32)のboolean TryParse(String s, out int)  のTry~をまねたものです。ArgumentNullExceptionくらいしかスローされません。 > c++のmap::insertは(4)+α  +αにするならoutキーワードがないので、専用のクラス(TrialResult<T> { T result; bool succeeded; })みたいなのが要りますね。 > もっとわかりやすい名前がほしい  こればかりは、何も言い逃れできませんね。もうちょい頑張ってみます。

関連するQ&A