前面一篇文章介紹了兩個經常使用函數式接口Supplier
和Consumer
接口,今天接着講另外另個重要函數式接口Predicate
和Function
接口。這幾個接口在Java中應用普遍,比方Stream流式API中就常常用到。java
當咱們須要對某種數據類型進行判斷,獲得一個boolean值結果時候,能夠採用java.util.function.Predicate<T>
接口。比方說對傳進來的List判斷是否包含某個特定字符PHP。app
咱們有時候須要進行業務判斷,假設我要實現一個功能入參爲List,若是List參數知足某個條件則輸出對應的結果。比方說下面的代碼checkchar()
若是入參list1
知足某個條件那麼輸出System.out.println("知足對應條件")
,具體條件是什麼還不肯定,多是判斷List中是否包含某個元素,大小是否符合要求。具體由調用方來實現。ide
private static boolean checkChar(List list1, Predicate<List> predicateList) { boolean rs = predicateList.test(list1); if (rs) { System.out.println("知足對應的條件"); } return rs; }
下面咱們實現main方法調用上面checkchar()
方法,而且經過lambda表達式來實現裏面具體判斷條件。函數
public static void main(String[] args) { List list1 = new ArrayList(); list1.add("PHP"); list1.add("JAVA"); list1.add("C++"); boolean rs = checkChar(list1, s -> { return s.contains("PHP"); }); if (rs) { System.out.println("list1中包含PHP 字符"); } else { System.out.println("list1中不包含PHP 字符"); } }
main
方法中,調用checkChar()
方法的時候,傳入lambda表達式s->{return s.contains("PHP")}
來進行判斷。這意思就是說在調用checkChar
方法的時候若是list1
列表中包含PHP
這個元素執行System.out.println("知足對應的條件")
語句。ui
上述代碼執行結果爲:this
知足對應的條件 list1中包含PHP 字符
上面咱們說了單個條件判斷,若是想多個條件判斷怎麼辦?可使用Predicate的and()
方法。code
咱們先定義一個函數,這個函數裏會進行兩個判斷,兩個判斷具體的邏輯由外部傳過來。對象
private static boolean checkChar2(List list1, Predicate<List> pre, Predicate<List> other) { return pre.and(other).test(list1); }
main
方法中,傳入兩個判斷邏輯s -> { return s.contains("PHP");}
和 s -> { return s.contains("C++");}
,而後經過Predicate.and()
方法執行與操做。接口
public static void main(String[] args) { List list1 = new ArrayList(); list1.add("PHP"); list1.add("JAVA"); list1.add("C++"); boolean rs = checkChar2(list1, s -> { return s.contains("PHP"); }, s -> { return s.contains("C++"); }); if (rs) { System.out.println("list1同時有PHP和C++字符"); } else { System.out.println("list1不知足同時有PHP和C++字符"); } }
上述代碼的執行結果爲:three
list1同時有PHP和C++字符
"與"、"或"咱們已經瞭解了,剩下還有一個"非"(取反)操做,咱們看一下取反操做negate
如何使用。
Predicate
的negate()
方法以下:
default Predicate<T> negate() { return (t) -> !test(t); }
從源碼咱們能夠看到negate
方法是在執行了test()
方法以後,對結果boolean
值進行取反而已。請注意,必定要先調用negate
方法而後調用test
方法 ,這個跟and
和or
方法同樣:
private static boolean checkNotChar(List list1, Predicate<List> pre1) { return pre1.negate().test(list1); } public static void main(String[] args) { List list1 = new ArrayList(); list1.add("PHP"); list1.add("JAVA"); list1.add("C++"); boolean rs = checkNotChar(list1, s -> { return s.contains("C#"); }); if (rs) { System.out.println("list1沒有C#"); } else { System.out.println("list1有C#"); } }
上述代碼執行結果爲:
list1沒有C#
java.util.function.Function<T,R>
至關於數據中的函數,一個類型的數據做爲輸入獲得另外一個類型數據的輸出。
Function
中執行轉換的方法爲抽象方法R apply(T t)
,該方法根據參數T
類型數據獲取類型爲R
的結果。好比下面我要將String
類型轉化爲Integer
類型。具體如何轉換由調用方經過lambda
來決定。
咱們先定義轉換的方法:
private static Integer transfer(String param, Function<String, Integer> function) { int num = function.apply(param); return num; }
具體轉換邏輯在main
方法中定義:
public static void main(String[] args) { String str = "99"; int num = transfer(str, s -> (Integer.parseInt(s) + 1));//這裏定義具體的轉換邏輯 System.out.println("DemoFunc執行結果爲" + num); }
若是咱們想作多步轉換那麼就須要用到andThen()
方法了,這些具體轉換的實如今調用放經過lambda來實現。
我先定義一個級聯轉換的方法chainTransfer
,該方法中傳入三個Function
依次通過one,two,three進行轉換,而後返回結果。
private static Integer chainTransfer(String str, Function<String, Integer> one, Function<Integer, Integer> two, Function<Integer, Integer> three) { int num = one.andThen(two).andThen(three).apply(str); return num; }
下面在main
方法中實現3個Function
而後調用轉換函數chainTransfer
:
public static void main(String[] args) { int num = chainTransfer("9", str -> Integer.parseInt(str) + 10, i -> i *= 10, i -> i + 5); System.out.println("轉換後的結果爲:" + num); }
咱們執行上面main
方法結果爲:
轉換後的結果爲:195
具體轉換步驟爲:
1. 先將9轉換成Integer類型而後+10,對應Integer.parseInt(str) + 10,獲得19; 2. 而後乘以10,獲得19*10 = 190; 3. 第三部加5,獲得190+5 = 195。
固然定義這個方法的時候有一個要注意的,依賴被調用的Function
參數類型要是適配,比方說Function<String,Integer> one
入參爲String
返回值爲Integer
,那麼後面Function two
的入參必須是Integer
。即前一個Function
的返回值跟後一個Function
入參類型應該兼容。
前面咱們說了,即前一個Function
的返回值跟後一個Function
入參類型應該兼容。由於前一個Function
是後一個Function
的入參,在函數調用中當實際入參是形參的子類那麼是兼容的。
即以下的轉換函數式兼容的:
private static User objChainTransfer(String str, Function<String, VipUser> one, Function<User, User> two) { User u = one.andThen(two).apply(str); return u; } }
前面一個Function
返回的是VipUser
,其爲第二個Function
的入參User
的子類。咱們在main
函數中調用上面的函數,其代碼以下:
public static void main(String[] args) { User u = objChainTransfer("19", str -> { return new VipUser("name" + str, str); }, vipUser -> { vipUser.setName(vipUser.getName() + "_new"); return vipUser; }); System.out.println("轉換後的結果爲:" + u); }
運行後其結果爲:
轉換後的結果爲:VipUser{name='name19_new', id='19'}
這段代碼作了以下事情:
1. 咱們先建立一個`VipUser`對象 2. 修改name屬性, 3. 返回User對象。
進一步咱們能夠分析源碼:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); }
源碼中,andThen
方法中Function<? super R, ? extends V> after
,表示after
的這個Function
的入參必須是R的超類,其中R是第一個Function
的返回值。
具體能夠查看Function.java的源碼:
public interface Function<T, R> { /** * Applies this function to the given argument. * * @param t the function argument * @return the function result */ R apply(T t); //... }