Javaでnullチェックを行わずに値を取得する


15

多くの場合、データ階層から値をフェッチするときにNullPointerExceptionsを回避するためにnullチェックを行います。NullPointerExceptionsはエラーを起こしやすく、多くの定型文を必要とします。

オブジェクトを取得するときにnullチェックをスキップできる非常に単純なルーチンを作成しました...

public final class NoNPE {

    public static <T> T get(NoNPEInterface<T> in) {
        try {
            return in.get();
        } catch (NullPointerException e) {
            return null;
        }
    }

    public interface NoNPEInterface<T> {
        T get();
    }
}

私はこのように少し使います...

Room room = NoNPE.get(() -> country.getTown().getHouses().get(0).getLivingRoom());

上記の結果、すべての親レベルをnullチェックする必要なく、Roomオブジェクトまたはnullが取得されました。

上記についてどう思いますか?問題のあるパターンを作成していますか?あなたの意見ではこれを行うより良い方法はありますか?


1
明らかにJava 8を使用しているので、java.util.Optional欠損データを表すためにnullの代わりに使用するようにアプリケーションを再設計することを検討することをお勧めしますか?これは単に鎖の末端に障害状態を返すのではなく、便利な場合のためにあなたが記述の両方のユーティリティおよびデフォルトのデータを続けていくしたいケースを提供してい...
Periata Breatta

あなたは本質的にOption(またはMaybe)モナドを再発見したと思います:)
Andres F.

Tまたはnullの代わりにOptionalを返すこともできます。この方法では、orElse()メソッドを直接使用できます。18か月後ですが、誰かを助けることができました。
ベンジ

別のアプローチは、この記事に記載されているillegalargumentexception.blogspot.com/2015/03/...そのうちの一つは、非常に興味深い構文を持つライブラリの名前kludje使用され、
Benj

回答:


13

あなたのソリューションは非常にスマートです。私が見る問題は、あなたがなぜあなたが得たのnullかわからないという事実です?家に部屋がなかったからでしょうか?町には家がなかったからでしょうか?国に町がなかったからでしょうか?それnullは、位置が1以上の家がある場合でも、エラーのためにコレクションの0の位置にあったからでしょうか?

NonPEクラスを拡張的に使用すると、深刻なデバッグの問題が発生します。nullより深いエラーを隠している可能性があるものを静かに取得するよりも、チェーンが正確にどこで壊れているかを知る方が良いと思います。

これもデメテル法則に違反していcountry.getTown().getHouses().get(0).getLivingRoom()ます:。多くの場合、いくつかの良い原則に違反すると、そのような原則に違反することによって引き起こされる問題を解決するために、非正統的なソリューションを実装する必要が生じます。

私の推奨事項は、注意して使用し、列車の残骸アンチパターンで負担しなければならない設計上の欠陥を解決することです(したがって、NonPEどこでも使用する必要はありません)。そうしないと、検出が難しいバグが発生する可能性があります。


素晴らしい答え。はい、チェーンのどこでヌルを取得したかわかりません。多くの場合、私は気にせず、nullチェックをする必要はありませんが、コードが読みやすく、定型的なエラーが発生しにくいことを意味します。しかし、はい、親オブジェクトがnullである場合に別の論理的決定を行う必要があるいくつかのケースでは正しいので、これは問題を引き起こします。そこでは、従来のメソッドまたはOptionalクラスがより安全なソリューションになる可能性があります。
ユーリッグジョーンズ

一般に、Optionモナドを使用する場合、チェーンのどこに値がないかは気にしません。気にするときは、おそらくのような別のタイプを使用するでしょうEither
アンドレスF.

OPのアプローチは、C#6 ?.および?[]演算子に似ています。このようなものを使用する場合の1つの例は、サーバー側の階層設定です。var shouldDoThing = settings?.a?.b?.c ?? defaultSetting;なぜその一部がヌルだったのか誰が気にしますか?設定を取得できなかったのかもしれません。設定のセクションを削除することにしたのかもしれません。いずれにせよ、サーバーの設定を取得することを実際に期待することはできないため、通常はデフォルトを設定することをお勧めします。 。
クリス

今では、デフォルトをローカライズして、通常のアクセスで必要な値を取得するよりも厳密に良いとか悪いとは言いませんsettings.a.b.c。繰り返しますが、これは単一の孤立した例です。
クリス

10

アイデアは素晴らしく、実際には本当に良いです。Java 8にはOptionalタイプが存在するため、詳細な説明はJava Optional typeにあります。あなたが投稿したものの例は

Optional.ofNullable(country)
    .map(Country::getTown)
    .map(Town::Houses);

そしてさらに。


1
はい、Java 8とGuavaの両方からOptionalクラスを知っていましたが、これらは本当に便利です。ただし、通常はコードを読みにくくし、パフォーマンスも少し低下させるため、オブジェクトを取得することはできません。しかし、利点は、Optionalクラスが提供する非常に便利な演算子が多数あることです。
ユーリッグジョーンズ

3
@EurigJonesコードのパフォーマンスが低下するとは思わない。見る人の目にはOptional読みやすいが、私は、あなたの提案とは異なり、それは非常に一般的なイディオムであるという理由だけで、2つのより読みやすい解決策だと主張します。それはあなたのものよりもさらに簡潔です!
アンドレスF.

0

あなたのメソッドは意図した目的には十分に機能しnullますが、NullPointerExceptionデザインが悪いように聞こえるとsを返します。

null可能な場合はs を避け、何かを表すか特別な意味を持つ場合にのみそれらを渡し、それらが何かを表す/意味する場合にのみ返すようにしますNullPointerException。これにより、バグや混乱を回避できます。であるObject必要がない場合、をスローnullするNullPointer必要があります。オブジェクトをnull渡すことができる場合、オブジェクトが渡されても何も問題はありません。それ以外の場合、上記のメソッドは機能します。


0

私はあなたの痛みを感じることができますが、提案された解決策は悪い考えです。

  • ゲッターの1つが他の理由でNPEをスローした場合、それを無視します。
  • その内部ラムダが恐ろしいコードに成長するリスクがあります。たとえば、町に家がないときに特別な定数を返す新しい要件がある場合、怠zyなプログラマーはラムダを拡張し、すべてをラップしたままにすることができNoNPE.getます。
  • すでに述べたように、Optional.mapあなたが探しているものです。
  • NullPointerExceptionの新しいインスタンスを作成することのペナルティは、しばしば重大です。特にコールスタックが大きくなるにつれて、数マイクロ秒になります。ユーティリティがどこで使用されるかを予測するのは困難です。

補足として、NoNPEInterfaceはの複製ですjava.util.function.Supplier

場合によっては、多くのフレームワークに存在する式評価ユーティリティの使用を検討することもできます(例:EL、SpEL):

evaluateProperty(country, "town.houses[0].livingRoom")

Webページテンプレートは問題ありませんが、通常は開発に時間がかかり(コンパイル時のチェックはありません)、実行に時間がかかります。
ケビンクライン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.