2017-06-13 60 views
6

比方說,我有這樣的必要代碼:如何將函數列表應用於Java 8中的值?

List<Function<T, T>> functions = ... 
    T value = ... 
    for (Function<T, T> function : functions) { 
     value = function.apply(value); 
    } 

我怎樣寫這個在功能風格(像什麼倍斯卡拉呢)?

+1

你可以將值和'#forEach'設置爲'functions'列表,但這並不能真正幫助你獲得任何東西(並且不是真正的功能)。總的來說,代碼看起來很好,java是一種命令式語言。 – Rogue

+1

[使用Java-8中的函數ArrayList](https://stackoverflow.com/questions/30274124/working-with-an-arraylist-of-functions-in-java-8)這將有助於 –

+4

看起來很接近到[這一個](https://stackoverflow.com/q/32338553/2711488)... – Holger

回答

10

這款剛剛問了幾個小時前的Consumer ...你可以減少他們到一個單一的功能並應用:

@SafeVarargs 
private static <T> Function<T, T> combineF(Function<T, T>... funcs) { 
    return Arrays.stream(funcs).reduce(Function.identity(), Function::andThen); 
} 
+4

雖然在語義上相同,但是'.reduce(Function :: andThen).orElse(Function.identity())'可能會產生一個稍微高效的函數。 – Holger

+0

@Holder是否有使用'.reduce(Function :: andThen).orElseGet(Function :: identity)'的問題? – srborlongan

+1

@srborlongan之前已經討論過,請參閱:https://stackoverflow.com/questions/44261253/when-i-need-to-use-optional-orelseget-over-optional-orelse/44261755#44261755 – Eugene

1

這裏有尤金的答案變體,只是爲了好玩

public static <T> Function<T, T> combine(List<Function<T, T>> functions) { 
    return new Object() { 
     Function<List<Function<T, T>>, Function<T, T>> combiner = list -> 
      list.size() == 1 ? list.get(0) : 
      list.get(0).andThen(this.combiner.apply(list.subList(1, list.size()))); 
    }.combiner.apply(functions); 
} 

這將創建一個匿名內部類,其屬性是一個遞歸lambda。此屬性名爲combiner,它是一個高階函數,它將函數列表作爲參數並返回函數作爲結果。如果列表僅包含一個元素,則該高階函數返回列表的第一個函數,或者將andThen應用於列表的第一個函數,該函數帶有遞歸調用帶有子列表的高階函數的函數從第二個元素開始的函數。

匿名內部類是需要的,因爲遞歸lambda只能被定義爲類的屬性。

毋庸置疑,這比流式處理列表更復雜,並且使用二元運算符Function::andThen減少。此外,遞歸lambda表達式不是免費的:他們使用堆棧進行遞歸調用。

+0

除了創建lambdas字段以進行遞歸之外,Java 8中另一種(不太直觀的)方法是使用[Y組合器](http://rosettacode.org/wiki/Y_combinator#Java)。 – srborlongan

+1

@srborlongan或[trampolines](http://raganwald.com/2013/03/28/trampolines-in-javascript.html)... –

相關問題