傳遞方法:
假設 你有一個Apple類,它 有一個getColor方法,還有一個變量inventory保存着一個Apples的列表。你可能想要選出所 有的綠蘋果,並返回一個列表。通常我們用篩選(filter)一詞來表達這個概念。在Java 8之前, 你可能會寫這樣一個方法filterGreenApples:
1 public static List<Apple> filterGreenApples( List<Apple> inventory ) 2 { 3 List<Apple> result = new ArrayList<>(); for ( Apple apple : inventory ) 4 { 5 if ( "green".equals( apple.getColor() ) ) 6 { 7 result.add( apple ); 8 } 9 } 10 return(result); 11 }
但是接下來,有人可能想要選出重的蘋果,比如超過150克:
public static List<Apple> filterHeavyApples( List<Apple> inventory ) { List<Apple> result = new ArrayList<>(); for ( Apple apple : inventory ) { if ( apple.getWeight() > 150 ) { result.add( apple ); } } return(result); }
這 兩個方法只有一行不同: if里面高亮的那行條件。
Java 8你可以這樣寫:
1 public static boolean isGreenApple( Apple apple ) 2 { 3 return("green".equals( apple.getColor() ) ); 4 } 5 6 7 public static boolean isHeavyApple( Apple apple ) 8 { 9 return(apple.getWeight() > 150); 10 } 11 12 13 public interface Predicate<T>{ 14 boolean test( T t ); 15 } 16 17 static List<Apple> filterApples( List<Apple> inventory, Predicate<Apple> p ) 18 { 19 List<Apple> result = new ArrayList<>(); 20 for ( Apple apple : inventory ) 21 { 22 if ( p.test( apple ) ) 23 { 24 result.add( apple ); 25 } 26 } 27 return(result); 28 }
要用它的話,你可以寫:
1 filterApples(inventory, Apple::isGreenApple); 2 或者 3 filterApples(inventory, Apple::isHeavyApple);
注:
什么是謂詞? 前 面 的 代 碼 傳 遞 了 方 法 Apple::isGreenApple ( 它 接 受 參 數 Apple 並 返 回 一 個 boolean)給filterApples,后者則希望接受一個Predicate<Apple>參數。謂詞(predicate)它接受一個參數值,並返回true或false。你 在后面會看到, Java 8也會允許你寫Function<Apple,Boolean>,但用Predicate<Apple>是更標准的方式,效率也會更高一 點兒,這避免了把boolean封裝在Boolean里面
傳遞 Lambda
把方法作為值來傳遞顯然很有用,但要是為類似於isHeavyApple和isGreenApple這種可能只用一兩次的短方法寫一堆定義有點兒煩人。不過Java 8也解決了這個問題,它引入了一套新
記法(匿名函數或Lambda),讓你可以寫
filterApples(inventory, (Apple a) -> "green".equals(a.getColor()) );
或者
filterApples(inventory, (Apple a) -> a.getWeight() > 150 );
甚至
filterApples(inventory, (Apple a) -> a.getWeight() < 80 || "brown".equals(a.getColor()) );
所以,你甚至都不需要為只用一次的方法寫定義;代碼更干凈、更清晰,因為你用不着去找自己到底傳遞了什么代碼。但要是Lambda的長度多於幾行(它的行為也不是一目了然)的話,那你還是應該用方法引用來指向一個有描述性名稱的方法,而不是使用匿名的Lambda。你應該以代碼的清晰度為准繩。