2017-02-08 15 views
2

を襲ったユーザ嗜好システムとアプリケーションの次のユースケースを考えてみましょう:オプションの `orElse`遅延評価のパフォーマンスにリードを失敗は

我々は好みMyFlagのbool値を取得したいです。
最高の場合、現在のユーザーの設定から使用することをお勧めします。
これが失敗した場合、MyFlagをデフォルト設定から取得します。
それでも失敗した場合は、スローします。

設定はサーバー上にあります。この接続は遅く、失敗する可能性があります。
設定を取得して優先権を取得することもできます。
ので、使用javasのOptionalsをすることができます:ここ

public static boolean getMyFlag()throws NoSuchElementException 
{ 
     return getUserOrDefaultPreference("MY_FLAG"); 
} 

private Boolean getUserOrDefaultPreference(String preferenceName) throws NoSuchElementException 
{ 
    return Optional.ofNullable(getConnection())    // get slow connection 
     .map(connection -> connection.getUserSettings())  // get user settings 
     .map(settings -> settings.getPref(preferenceName)) // return preference 
     .orElse(slowlyGetDefaultPreference(preferenceName)); // or else return default value 
} 

private Boolean slowlyGetDefaultPreference(String preferenceName) throws NoSuchElementException 
{ 
    return Optional.ofNullable(getConnection())    // get slow connection 
     .map(connection -> connection.getDefaultSettings()) // get default settings 
     .map(settings -> settings.getPref(preferenceName)) // return preference 
     .orElseThrow(() -> new NoSuchElementException()); // if any of the above fails throw 
} 

問題は、接続が非常に遅くなることができるということです。 .orElse(slowlyGet...);が呼び出されると、func slowlyGetDefaultPreference()が最初に評価されます。これは、オプションが空であるか値があるかどうかに関係なく、最初に評価されます。これはパフォーマンスのペナルティですが、私は避けなければなりません。

.orElseGet(() -> slowlytGet..)でサプライヤを使用しようとしましたが、同じ問題が発生しました。

private Boolean getUserOrDefaultPreference(String preferenceName) throws NoSuchElementException 
{ 
    Optional<Boolean> opt = Optional.ofNullable(getConnection()) 
     .map(connection -> connection.getUserSettings()) 
     .map(settings -> settings.getPref(preferenceName)); 

    if(opt.isPresent()) 
    { 
     return opt.get(); 
    } 
    else 
    { 
     slowlyGetDefaultPreference(preferenceName)); 
    } 
} 

同じは私が支払うことをしたくないとして、例外をスローするために保持している:

だから私の唯一の頼みの綱は、読みやすさの観点から、全オプションの流れを台無しに醜いisPresent()アンチパターンは、あります1つを構築するコスト。

ここに何かが見つからない、またはこれが唯一の解決策ですか?

+0

'orElseGet'は最後の例とまったく同じように動作するはずですが、私はなぜそれが'orElse' – Magnus

+0

@Magnusデバッガでコードをステップ実行したところ、' orElse'に対して 'getSlow ..()'が呼び出されました。 –

+1

はい、orElseGetからの評価は、 'orElseGet'の前のある関数がnullオブジェクトを持っている場合にのみ呼び出されるためです。しかし、あなたが 'orElse'を使うと、常に – MateuszW90

答えて

1

私はそれだけで"smart"を印刷し、この試験した場合:

public class SampleJava { 
    public static String stupid() { 
     System.out.println("stupid"); 
     return "stupid"; 
    } 
    public static void main(String[] args) { 
     System.out.println(Optional.ofNullable("smart").orElseGet(() -> stupid())); 
    } 
} 
3

Optional.ofNullable()orElseGet前にいくつかのobejctがnullだったとき、orElse()orElseGet(lambdas)間の差は、最初の関数が常に呼び出されますが、orElseGetが呼び出されます。

それはあなたがorElse()から毎回メソッドを呼び出したくない場合、あなたはあなたの例ではorElseGet()

を使用する必要があり、意味、あなたの方法のためslowlyGetDefaultPreference(preferenceName)orElseGet()

return Optional.ofNullable(getConnection())    // get slow connection 
    .map(connection -> connection.getUserSettings())  // get user settings 
    .map(settings -> settings.getPref(preferenceName)) // return preference 
    .orElseGet(() -> slowlyGetDefaultPreference(preferenceName)); 

を使用してください次に、あなたがいないコーディング最後のメソッドを評価すると、マップ関数内のすべてのオブジェクトが0でない場合、null

+0

あなたは正しいです。その間の事は確かに「ヌル」でした。神、愚かな私。 –

+0

だからこそ、あなたは常に 'slowlyGetDefaultPreference(preferenceName)'を呼び出します。お力になれて、嬉しいです – MateuszW90