2017-05-29 78 views
5

我有一個關於lambda表達式可重用性的問題,沒有代碼重複。例如,如果我有一個幫助器方法,我可以很容易地將它編碼爲一個靜態方法,並且可以從其他類中引用它而不存在代碼重複。這將如何在lambda表達式中工作? 例子:我有以下的靜態方法寫入lambda表達式vs靜態方法

public class MyUtil { 

    public static int doubleMe(int x) { 
     return x * 2; 
    } 
} 

我可以重複使用而無需在整個項目

public class A { 

    public void someOtherCalculation() { 
     MyUtil.doubleMe(5); 
    } 
} 

public class B { 

    public void myCalculation() { 
     MyUtil.doubleMe(3); 
    } 
} 

多處代碼重複同樣的方法它是如何工作的,當涉及到一個lambda函數,編寫一次函數並在多個類中使用相同的函數。

Function<Integer, Integer> doubleFunction = x -> x * 2; 

在我的例子中,我會在哪寫上面的lambda函數,以及如何在類A和B中重複使用相同的函數?

+3

「代碼重用」在這裏是一個錯誤的目標。代碼_expressiveness_是需要的。使用不重複使用代碼的lambda有什麼可能的危害,以及你有什麼證據證明它沒有? Lambdas適用於許多不同的函數可以在算法中替代。你會爲它們寫一個明確的靜態方法,併爲每個方法創建一個方法參考,所以你可以說:「看,媽媽,我正在使用lambda表達式!」?在這種情況下傳統使用lambdas是否更有意義?您尋求的_real_工程優勢是什麼? –

+0

如果你想重用一個函數,那麼定義一個實現Function函數接口的類。靜態方法不是一個函數。 – xgbuils

回答

6

我會在哪裏寫上面的lambda函數

因爲你的函數沒有引用任何領域,它是適當的把它放在一個靜態的最終場:

class Utility { 
    public static final Function<Integer,Integer> doubleFunction = x -> x * 2; 
} 

我將如何在A和B級重複使用它?

你會稱其爲Utility.doubleFunction,並通過它在需要它的背景:

callMethodWithLambda(Utility.doubleFunction); 

注意方法的引用讓你定義一個函數,並使用它,彷彿它是拉姆達:

class Utility { 
    public static Integer doubleFunction(Integer x) { 
     return x*2; 
    } 
} 
... 
callMethodWithLambda(Utility::doubleFunction); 

這種做法是非常靈活的,因爲它可以讓你重複使用在多種環境中相同的代碼爲你找到合適的。

3

真的,匿名函數適用於需要重用代碼不是的情況。

笨啞的例子,但假設你正在使用map爲列表中的每個數字添加兩個。如果這是你可能需要的一種常見操作,那麼在一個數字上加上2的靜態函數比編寫相同的lambda表達式更有意義。

但是,如果您有一個將列表中的兩個添加到列表中的單個函數,那麼在本地將「add two」函數定義爲lambda表達式更有意義,因此您不要使用任何地方不需要的代碼來插入類其他。

在編寫廣泛使用高階函數的Clojure時,創建本地匿名函數來整理我正在編寫的「全部」函數中的代碼是很常見的。絕大多數這些匿名函數在「全局」範圍(或類範圍)中是非感性的;特別是因爲它們通常關閉局部變量,所以它們不可能是全局的。

+1

我一直認爲這一點,但從來沒有讀過它。很有幫助。 – ftor

2

使用lambda表達式,您不必擔心可重用性(實際上,大多數lambda表達式都沒有被重用)。如果你想有一個Function指針指向這個方法,你可以聲明一個象下面這樣:

Function<Integer, Integer> doubleFunction = MyUtil::doubleMe; 

,並傳遞給任何方法或流應用/地圖,如:

public static void consume(Function<Integer, Integer> consumer, int value){ 
    System.out.println(consumer.apply(value)); 
} 

public static void main(String[] args) throws Exception{ 
    Function<Integer, Integer> doubleFunction = MyUtil::doubleMe; 
    consume(doubleFunction, 5); 
} 
2

從不同其他答案。我想用TDD方式回答你的問題。

IFdoubleMe是如此簡單,因爲你已經寫了,那就是clrealy你應該停止濫用法表達參考,只是直接把它作爲一種常見的方法調用。

IFdoubleMe非常複雜,要測試doubleMe獨立的,你需要做的依賴注入隱顯式依賴於測試是否可以通過其cummunication協議一起工作。但是java不能直接引用方法,除非你使用反射api Method /使用匿名類實現SAM接口,它將請求委託給jdk-8之前的方法。您可以將方法表達式引用引用到jdk-8中的一個功能接口,這是多麼幸福的事情。這樣就可以使暗指的依賴,通過使用功能接口明確的,那我想寫成下面的一些通訊協議測試:

@Test 
void applyingMultiplicationWhenCalculating???(){ 
    IntUnaryOperator multiplication = mock(IntUnaryOperator.class); 
    B it = new B(multiplication); 

    it.myCalculation(); 

    verify(multiplication).applyAsInt(3); 
} 

那麼你的類,如作爲B應用依賴注入更像如下:

public class B { 
    IntUnaryOperator multiplication; 

    public B(IntUnaryOperator multiplication){ 
      this.multiplication = multiplication; 
    } 

    public void myCalculation() { 
      multiplication.applyAsInt(3); 
    } 
} 

THEN可以重用的方法通過參考的方法表達參照功能接口,如下:

A a = new A(MyUtil::doubleMe); 
B b = new B(MyUtil::doubleMe);