2016-12-04 39 views
2

我寫下面的方法的實用類(等等)有所不同:迴避javac的「曖昧」預警重載方法,只有參數拉姆達是無效或非空

class FunctionNamingUtils { 
    public static <T> Consumer<T> named(String name, Consumer<T> delegate) { 
     class NamedConsumer implements Consumer<T> { 
      @Override public void accept(T t) { delegate.accept(t); } 
      @Override public String toString() { return name; } 
     } 
     return new NamedConsumer(); 
    } 

    public static <T, R> Function<T, R> named(String name, Function<T, R> delegate) { 
     class NamedFunction implements Function<T, R> { 
      @Override public R apply(T t) { return delegate.apply(t); } 
      @Override public String toString() { return name; } 
     } 
     return new NamedFunction(); 
    } 
} 

編譯器與抱怨:

警告:JAVA: 命名(java.lang.String中,java.util.function.Consumer)在...是 與 命名(java.lang.String中,JAVA可能不夠明確。 util.function.Function)in ...

我確實得到了警告的目的 - 取決於lambda是返回一個值還是一個空值,我們將以某種方式或另一種方式返回,以及單個語句lambdas很難看清。

事情是,在這種情況下,這正是我們想要的,我想使用重載來減少必須記住兩個方法名稱的相同功能的認知負擔(我已經不得不妥協其中namedPredicate與布爾函數衝突)。

我正在尋找任何想法 - 要麼禁止警告,要麼以不同的方式表達API。重點在於客戶端的清晰性和易用性。

我只關心Java 8+。

+3

如果您已經與namedPredicate妥協了,那麼如果您還使用namedFunction和namedConsumer,則API會更加一致。 –

+0

我同意JB。當然這是一個風格問題,但我經常發現**重載**方法往往會**超負荷**我的大腦。例如由於這種情況。所以我的2美分也是:只爲方法使用不同的名字。 – GhostCat

+0

簡潔性也很重要,特別是對於原始概念。否則,你最終會得到像Spring Framework這樣的名字(沒有冒犯的意思,但我認爲它不適合公用事業)。 – ddimitrov

回答

0

其實我對lambda的理解並不完整。事實證明,返回值的任何lambda都可以合法地用於void lambda的位置。

errorprone/FunctionalInterfaceClash

JLS 15.12.2.1引用表示,其lambda表達式體是一個語句表達 與功能接口,其功能類型兼容是 空隙返回或值返回:

  • 如果滿足以下所有條件,則λ表達式(§15.27)可能與 函數接口類型(§9.8)兼容:

  • 目標類型的函數類型的arity與lambda表達式的參數 相同。如果目標類型的函數類型具有無效返回 ,那麼lambda體或者是語句表達式

  • (第14.8節)或無效兼容塊(第15.27.2節)。如果目標類型的 函數類型具有(非空)返回類型,則lambda體是 表達式或值兼容塊(第15.27.2節)。

換句話說,鑑於上述實施,使消費者和功能拉姆達會解決得很好,但再有就是我們所希望使用的實際返回一個lambda來實現消費者的使用情況值。

例如這兩個會失敗:

Functions.named(name, Objects::requireNonNull); 
Functions.named(name, it -> Objects.requireNonNull(it)); 

爲了使它的工作,我們需要增加明確的語句塊這樣的:

Functions.named(name, it -> { Objects.requireNonNull(it); }); 

雖然這是一個邊緣的情況下,我可以記錄它在API中,這改變了可讀性權衡,所以現在我正在將方法重命名爲:

Functions.fun(name, delegate) 
Functions.con(name, delegate) 
Functions.pre(name, delegate) 
Functions.sup(name, delegate) 

雖然沒有named那麼好,但它仍然可讀且一致。

我簡單地考慮了namedFunction樣式名稱,但考慮到在代碼庫中使用這些樣式的頻率,我寧願讓它們更簡潔。