取得メソッドは、戻り値を生成できないときに「null」を返すか、例外をスローする必要がありますか? [閉まっている]

StackOverflow https://stackoverflow.com/questions/175532

  •  05-07-2019
  •  | 
  •  

質問

オブジェクトが見つかった場合にそれを返すことになっているメソッドがあります。

見つからない場合、私は:

  1. nullを返す
  2. 例外をスロー
  3. その他
役に立ちましたか?

解決

常に値を見つけることを期待している場合、値がない場合は例外をスローします。例外は問題があることを意味します。

値が欠落または存在する可能性があり、両方がアプリケーションロジックで有効な場合、nullを返します。

より重要:コードの他の場所で何をしていますか?一貫性が重要です。

他のヒント

それが本当にエラーである場合にのみ、例外をスローします。オブジェクトが存在しないことが予想される動作である場合は、nullを返します。

それ以外の場合は、好みの問題です。

原則として、メソッドが常にオブジェクトを返す必要がある場合は、例外を使用します。ときどきヌルを予測し、それを特定の方法で処理したい場合は、ヌルを使用してください。

あなたが何をするにしても、3番目のオプション:" WTF"を含む文字列を返すことを強くお勧めします。

nullがエラーを示さない場合は、nullを返します。

nullが常にエラーの場合、例外をスローします。

nullが例外である場合、2つのルーチンをコーディングします。 1つのルーチンは例外をスローし、もう1つは出力パラメーターでオブジェクトを返すブールテストルーチンであり、オブジェクトが見つからなかった場合、ルーチンはfalseを返します。

Tryルーチンを誤用することは困難です。 nullのチェックを忘れるのは本当に簡単です。

そのため、nullがエラーの場合、あなたはただ書きます

object o = FindObject();

nullがエラーでない場合、次のようなコードを記述できます

if (TryFindObject(out object o)
  // Do something with o
else
  // o was not found

先ほど述べたオプションを繰り返して、新しいオプションをいくつか追加しました:

  1. nullを返す
  2. 例外をスロー
  3. nullオブジェクトパターンを使用
  4. メソッドにブールパラメータを提供します。これにより、呼び出し元は、例外をスローするかどうかを選択できます
  5. 追加のパラメーターを提供して、呼び出し元が値を設定できるようにします。値が見つからない場合は、取得します

またはこれらのオプションを組み合わせることができます:

ゲッターのオーバーロードされたバージョンをいくつか提供して、呼び出し元がどちらに進むかを決定できるようにします。ほとんどの場合、最初のアルゴリズムのみが検索アルゴリズムの実装を持ち、他のアルゴリズムは最初のアルゴリズムのみをラップします。

Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);

実装を1つだけ提供することを選択した場合でも、そのような命名規則を使用して契約を明確にすることができます。これは、他の実装も追加することにした場合に役立ちます。

それを使いすぎてはいけませんが、特に、多くの異なるエラー処理規則で何百もの異なるアプリケーションで使用するヘルパークラスを作成する場合に役立ちます。

nullオブジェクトパターンを使用するか、例外をスローします。

使用しているAPIとの一貫性を保つ。

自分自身に問いかける:「オブジェクトが見つからないという例外的なケースですか?」プログラムの通常の過程で発生することが予想される場合は、例外を発生させないでください(例外的な動作ではないため)。

ショートバージョン:例外を使用して、プログラムの通常の制御フローを処理するのではなく、例外的な動作を処理します。

-アラン。

言語とコードが促進するかどうかによります: LBYL(跳躍する前に見てください) または EAFP(許可よりも許しを求める方が簡単)

LBYLは、値をチェックする必要がある(したがってnullを返す)ことを示しています
EAFPは、操作を試行して失敗するかどうかを確認する(例外をスローする)ことを指示します

上記に同意しますが、例外は例外/エラー条件に使用する必要があり、チェックを使用する場合はnullを返すのが最適です。


PythonでのEAFPとLBYL:
http://mail.python.org/pipermail/python-list /2003-May/205182.html Webアーカイブ

例外をスローする利点:

  1. 呼び出しコード内の制御フローをよりクリーンにします。 nullをチェックすると、try / catchによってネイティブに処理される条件分岐が挿入されます。 nullのチェックは、何をチェックしているのかを示すものではありません-期待しているエラーを探しているためにnullをチェックしていますか、それともダウンチェインでそれ以上渡さないようにnullをチェックしていますか
  2. 何が「null」かというあいまいさを取り除きます。 エラーを表すnullまたは値に実際に格納されているものはnullですか?その決定の基礎となるものが1つしかない場合は言いにくい。
  3. アプリケーションのメソッド動作間の一貫性が向上しました。例外は通常、メソッドシグネチャで公開されるため、アプリケーションアカウントのメソッドがどのエッジケースであり、どのような情報であるかをより理解できます。アプリケーションは予測可能な方法で反応できます。

例の詳細については、 httpを参照してください。 ://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/

例外は、契約による設計に関連しています。

オブジェクトのインターフェースは、実際には2つのオブジェクト間のコントラクトであり、呼び出し元はコントラクトを満たす必要があります。そうでない場合、レシーバーは例外で失敗するだけです。 2つの可能な契約があります

1)メソッドが有効なすべての入力。この場合、オブジェクトが見つからない場合はnullを返す必要があります。

2)一部の入力のみが有効です。つまり、見つかったオブジェクトになります。その場合、入力が正しいかどうかを呼び出し側が判断できるようにする2番目のメソッドを提供する必要があります。例

is_present(key)
find(key) throws Exception

IFおよび2番目のコントラクトの両方のメソッドを提供する場合のみ、何も見つからない場合に例外をスローできます!

nullを返すだけで、呼び出し元に依存して適切に処理することを好みます。 (より良い言葉がないため)例外は、このメソッドがオブジェクトを返すことを絶対に「確信」している場合です。その場合、失敗は例外的なものであり、投げるべきです。

オブジェクトが見つからないという意味によって異なります。

通常の状態の場合は、nullを返します。これは、たまに発生する可能性があるものであり、呼び出し元はそれを確認する必要があります。

エラーの場合、例外をスローします。呼び出し元は、オブジェクトが見つからないというエラー状態の処理方法を決定する必要があります。

どちらでも動作しますが、ほとんどの人は一般に、例外が発生した場合にのみ例外を使用することをお勧めします。

さらにいくつかの提案があります。

コレクションを返す場合は、nullを返すのを避け、空のコレクションを返します。これにより、nullチェックなしで列挙を処理しやすくなります。

.NET APIのいくつかは、オブジェクトが見つからない場合に本当に例外的な状況であるかどうかを選択できるようにするthrownOnErrorパラメーターのパターンを使用します。 Type.GetTypeはこの例です。 BCLのもう1つの一般的なパターンは、ブール値が返され、出力パラメーターを介して値が渡されるTryGetパターンです。

デフォルトまたは動作なしのバージョンのいずれかである場合がある状況では、Null Objectパターンを考慮することもできます。重要なのは、コードベース全体のnullチェックを回避することです。詳細については、こちらをご覧ください http://geekswithblogs.net/dsellers/archive /2006/09/08/90656.aspx

一部の関数では、パラメーターを追加します:

..., bool verify = true)

Trueはスローを意味し、Falseはエラー戻り値を返すことを意味します。このように、この関数を使用する人は両方のオプションを持っています。エラー処理を忘れる人のために、デフォルトはtrueである必要があります。

例外をスローする代わりにnullを返し、APIドキュメントでnull戻り値の可能性を明確に文書化します。呼び出し元のコードがAPIを尊重せず、nullのケースをチェックしない場合、おそらく何らかの「nullポインター例外」が発生します。とにかく:)

C ++では、オブジェクトを見つけるメソッドを設定する3つの異なる方法を考えることができます。

オプションA

Object *findObject(Key &key);

オブジェクトが見つからない場合はnullを返します。素敵でシンプル。これで行きます。以下の代替アプローチは、out-paramsを嫌わない人向けです。

オプションB

void findObject(Key &key, Object &found);

オブジェクトを受け取る変数への参照を渡します。オブジェクトが見つからない場合、メソッドは例外をスローしました。この規則は、オブジェクトが見つからないと実際に予想されない場合におそらくより適しています。したがって、例外をスローして、予期しないケースであることを示します。

オプションC

bool findObject(Key &key, Object &found);

オブジェクトが見つからない場合、メソッドはfalseを返します。オプションAに対するこの利点は、1つの明確なステップでエラーケースをチェックできることです。

if (!findObject(myKey, myObj)) { ...

nullが例外的な動作とはみなされない場合のみを参照してください。私は間違いなくtryメソッドであり、「本を読む」必要はありません。または「飛ぶ前に見る」ここで言ったように

そう基本的に:

bool TryFindObject(RequestParam request, out ResponseParam response)

これは、ユーザーのコードも明確になることを意味します

...
if(TryFindObject(request, out response)
{
  handleSuccess(response)
}
else
{
  handleFailure()
}
...

クライアントコードがfoundとnot foundの違いを知ることが重要であり、これが日常的な動作であると想定される場合は、nullを返すのが最善です。その後、クライアントコードは何をすべきかを決定できます。

通常、nullを返す必要があります。メソッドを呼び出すコードは、例外をスローするか、他の何かを試みるかを決定する必要があります。

またはオプションを返す

オプションは基本的に、クライアントにブースのケースを処理させるコンテナクラスです。 Scalaにはこの概念があります。APIを調べてください。

このオブジェクトにT getOrElse(T valueIfNull)のようなメソッドがあり、見つかったオブジェクトを返すか、クライアントが指定した代替を返します。

残念ながらJDKは一貫性がありません。リソースバンドル内の既存のキーにアクセスしようとすると、例外が見つかりません。マップから値を要求すると、値が存在しない場合はnullになります。そのため、見つかった値がnullになる可能性がある場合は勝者の答えを次のように変更し、見つからない場合は例外を発生させ、そうでない場合はnullを返します。そのため、1つの例外を使用してルールに従います。値が見つからない理由を知る必要がある場合は、常に例外を発生させます。または

オブジェクトへの参照を返すことになっている限り、NULLを返すことは適切です。

ただし、血まみれのものを返す場合(C ++の場合:「return& blah;」ではなく「return blah;」(または「blah」はポインターです)、返せません「オブジェクト」型ではないため、NULL。その場合、例外をスローするか、成功フラグが設定されていない空のオブジェクトを返すことが、問題へのアプローチ方法です。

例外処理のオーバーヘッドについて誰かが言及したとは思わないでください-例外をロードして処理するために追加のリソースが必要です呼び出し環境が適切であると解釈できる値を返します。

ここでのコンセンサスと思われるものに同意します(「見つからない」が通常の可能性のある結果の場合はnullを返し、状況のセマンティクスがオブジェクトを常に見つける必要がある場合は例外をスローします)。

ただし、特定の状況に応じて意味のある3番目の可能性があります。あなたのメソッドは、「見つかりません」で何らかの種類のデフォルトオブジェクトを返すことができますnullチェックや例外キャッチを必要とせずに常に有効なオブジェクトを受け取ることを保証する呼び出しコードを許可する条件を許可します。

nullを返します。例外はまさにそれです:コードが行うことは予期されていません。

例外は例外的である必要があります。 nullを返す nullを返すことが有効な場合

nullを返すことを好む-

呼び出し元がチェックせずに使用した場合、とにかくそこで例外が発生します。

発信者が実際に使用しない場合、 try / catch ブロックを課税しないでください

メソッドがコレクションを返す場合、空のコレクションを返します(上記のように)。ただし、Collections.EMPTY_LISTなどは使用しないでください。 (Javaの場合)

メソッドが単一のオブジェクトを取得する場合、いくつかのオプションがあります。

  1. メソッドが常に結果を見つける必要があり、オブジェクトを見つけられないことが実際の例外の場合、例外をスローする必要があります(Javaの場合は、未チェックの例外を指定してください)
  2. (Javaのみ)メソッドがチェック済み例外をスローすることを許容できる場合は、プロジェクト固有のObjectNotFoundExceptionなどをスローします。この場合、例外の処理を忘れた場合、コンパイラーはあなたに言います。 (これは、Javaで見つからないものを処理するための私の好みです。)
  3. 本当に問題ない場合、オブジェクトが見つからず、メソッド名がfindBookForAuthorOrReturnNull(..)のような場合、nullを返すことができます。この場合、ある種の静的チェックまたはコンパイラーチェックを使用することを強く思い出しますが、nullチェックなしで結果の逆参照を防ぎます。 Javaの場合、たとえばFindBugs( http://findbugs.sourceforge.net/manual/annotations.html)またはIntelliJ-Checking。

nullを返す場合は注意してください。あなたがプロジェクトの唯一のプログラマーではない場合、実行時にNullPointerExceptions(Javaまたはその他の言語で)が発生します!したがって、コンパイル時にチェックされないnullを返さないでください。

ライブラリまたは例外をスローする別のクラスを使用している場合は、再スローする必要があります。以下に例を示します。 Example2.javaはライブラリに似ており、Example.javaはそのオブジェクトを使用します。 Main.javaは、この例外を処理する例です。呼び出し側のユーザーに意味のあるメッセージと(必要に応じて)スタックトレースを表示する必要があります。

Main.java

public class Main {
public static void main(String[] args) {
    Example example = new Example();

    try {
        Example2 obj = example.doExample();

        if(obj == null){
            System.out.println("Hey object is null!");
        }
    } catch (Exception e) {
        System.out.println("Congratulations, you caught the exception!");
        System.out.println("Here is stack trace:");
        e.printStackTrace();
    }
}
}

Example.java

/**
 * Example.java
 * @author Seval
 * @date 10/22/2014
 */
public class Example {
    /**
     * Returns Example2 object
     * If there is no Example2 object, throws exception
     * 
     * @return obj Example2
     * @throws Exception
     */
    public Example2 doExample() throws Exception {
        try {
            // Get the object
            Example2 obj = new Example2();

            return obj;

        } catch (Exception e) {
            // Log the exception and rethrow
            // Log.logException(e);
            throw e;
        }

    }
}

Example2.java

 /**
 * Example2.java
 * @author Seval
 *
 */
public class Example2 {
    /**
     * Constructor of Example2
     * @throws Exception
     */
    public Example2() throws Exception{
        throw new Exception("Please set the \"obj\"");
    }

}

それは、実際にオブジェクトを見つけるかどうかに依存します。例外を何かを示すために使用するべきだという考え方に沿って、まあ、エラー、例外が発生した場合:

  • オブジェクトが見つかりました。オブジェクトを返す
  • オブジェクトが見つかりません。例外をスローする

それ以外の場合、nullを返します。

scroll top