基于Consumer接口、Predicate接口初使用
Consumer 接口
源碼
package java.util.function; import java.util.Objects; @FunctionalInterface public interface Consumer<T> { void accept(T t); default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
從源碼中可以得到,Consumer 接口是函數(shù)式接口,并且這個(gè)函數(shù)式接口的唯一抽象方法是沒有返回值的,也許大家會(huì)有疑惑,沒有返回值,那這個(gè)接口有什么用呢?當(dāng)然,這個(gè)接口不會(huì)給我們返回什么值,但是我們可以用來修改傳遞過來的參數(shù)啊,這樣比直接修改又多了什么優(yōu)點(diǎn)呢?額,自己挖坑?我也說不上來多了什么優(yōu)點(diǎn),我還很弱,不過我喜歡這種編程方式。
直接使用 accept()
舉個(gè)例子,假如用戶的 name 為 null,那么就可以給他設(shè)置一個(gè)默認(rèn)的 name ,想不到好的例子,感覺這個(gè)例子不是很合理,但是意思差不多。
User.java:
package entity; public class User { // 用戶默認(rèn)名字 public static final String DEFAULT_NAME = "Kaven"; // 用戶的年齡 private int age; // 用戶的名字 private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
testConsumer.java:
package test; import entity.User; import java.util.function.Consumer; public class testConsumer{ public static void main(String[] args){ Consumer<User> consumer = user -> user.setName(User.DEFAULT_NAME); User user = new User(); if(user.getName() == null) consumer.accept(user); System.out.println(user.getName()); } }
輸出:Kaven
使用 andThen()
從源碼可以得到,this 進(jìn)行 accept() 后,after 再進(jìn)行 accept(),相當(dāng)于進(jìn)行了兩次 accept() 。
default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; }
下面以小學(xué)成績(jī)單為例,假設(shè)小學(xué)成績(jī)單是由兩門單科成績(jī)(語(yǔ)文、數(shù)學(xué))和總分組成,當(dāng)我們需要修改其中一門成績(jī)的時(shí)候,我們是不是也需要修改總分呢?這是肯定的啊。當(dāng)然,這個(gè)例子也不是很合理。
Grade.java:
package entity; public class Grade { // 語(yǔ)文成績(jī) private int chinese_language; // 英語(yǔ)成績(jī) private int english; // 總分 private int total_score; public Grade(int chinese_language, int english){ this.chinese_language = chinese_language; this.english = english; this.total_score = chinese_language + english; } public int getChinese_language() { return chinese_language; } public void setChinese_language(int chinese_language) { this.chinese_language = chinese_language; } public int getEnglish() { return english; } public void setEnglish(int english) { this.english = english; } public int getTotal_score() { return this.total_score; } public void setTotal_score() { this.total_score = this.chinese_language + this.english; } }
testConsumerAndThen.java:
package test; import entity.Grade; import java.util.function.Consumer; public class testConsumerAndThen { public static void main(String[] args){ Consumer<Grade> total_score = grade -> { grade.setTotal_score(); }; Consumer<Grade> english = grade -> { grade.setEnglish(80); }; Grade grade = new Grade(80,70); System.out.printf("英語(yǔ)成績(jī)?yōu)椋?d\n",grade.getEnglish()); System.out.printf("總分為:%d\n",grade.getTotal_score()); english.andThen(total_score).accept(grade); System.out.println("修改英語(yǔ)成績(jī)后---------------"); System.out.printf("英語(yǔ)成績(jī)?yōu)椋?d\n",grade.getEnglish()); System.out.printf("總分為:%d\n",grade.getTotal_score()); } }
輸出:
英語(yǔ)成績(jī)?yōu)椋?0
總分為:150
修改英語(yǔ)成績(jī)后---------------
英語(yǔ)成績(jī)?yōu)椋?0
總分為:160
Predicate 接口
源碼
package java.util.function; import java.util.Objects; @FunctionalInterface public interface Predicate<T> { boolean test(T t); default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } default Predicate<T> negate() { return (t) -> !test(t); } default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
Predicate 接口也是函數(shù)式接口,調(diào)用接口的 test 方法會(huì)返回一個(gè)布爾類型的值,其實(shí)從 Predicate 接口的源碼中也可以看出來,這個(gè)接口的用處是什么。
以我的理解,是可以用來判斷傳遞過來的參數(shù)是否匹配一些條件。
使用 test()
我們還是使用 Consumer 接口的例子,當(dāng)用戶的 name 為 null 時(shí),給用戶設(shè)置默認(rèn)的 name。
我們可以用 Predicate 接口來判斷用戶的 name 是否為空,可能看起來比直接比較麻煩一點(diǎn)。
testPredicate.java:
package test; import entity.User; import java.util.function.Consumer; import java.util.function.Predicate; public class testPredicate { public static void main(String[] args){ Consumer<User> consumer = user -> user.setName(User.DEFAULT_NAME); Predicate<User> predicate = user -> { return user.getName() == null ; }; User user = new User(); if(predicate.test(user)) consumer.accept(user); System.out.println(user.getName()); } }
輸出:Kaven
一樣的效果。
使用 negate()
從源碼中可以得到,negate() 是返回一個(gè)對(duì) test() 的結(jié)果取一次反的 Predicate 實(shí)例。
default Predicate<T> negate() { return (t) -> !test(t); }
也可以這樣用,負(fù)負(fù)得正不是嗎。
if(!predicate.negate().test(user)) consumer.accept(user);
使用 and()
and() 返回一個(gè)對(duì)兩個(gè) test() 以 && 的方式的 Predicate 實(shí)例。
default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); }
在 User.java 里面加一個(gè)用戶默認(rèn)年齡屬性。
// 用戶默認(rèn)年齡 public static final int DEFAULT_AGE = 20;
當(dāng)用戶年齡不符合情況并且名字為空時(shí),就重新設(shè)置用戶的年齡和名字。
testPredicate.java:
package test; import entity.User; import java.util.function.Consumer; import java.util.function.Predicate; public class testPredicate { public static void main(String[] args){ Consumer<User> consumer = user -> user.setName(User.DEFAULT_NAME); Consumer<User> consumer_age = user -> user.setAge(User.DEFAULT_AGE); Predicate<User> predicate = user -> { return user.getName() == null ; }; Predicate<User> predicate_age = user -> { int age = user.getAge(); return (age <= 0 || age >=150); }; User user = new User(); if(predicate.and(predicate_age).test(user)) consumer.andThen(consumer_age).accept(user); System.out.println(user.getName()); System.out.println(user.getAge()); } }
輸出:
Kaven
20
Predicate接口還有兩個(gè)方法:
or()
or() 方法應(yīng)該很容易理解,or() 返回一個(gè)對(duì)兩個(gè) test() 以 || 的方式的 Predicate 實(shí)例。
default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); }
isEqual()
接口的靜態(tài)方法,看源碼也很容易理解,生成一個(gè)判斷是否與 targetRef equal的 Predicate 實(shí)例。targetRef 不為 null 時(shí),如果 targetRef 這個(gè)實(shí)例的類中沒有重載 Object 類的 equals() 方法或者 targetRef 這個(gè)實(shí)例本身就是 Object 類的實(shí)例,就會(huì)使用 Object 類的 equals() 進(jìn)行判斷,就只會(huì)判斷傳遞過來的參數(shù)的引用是否與 targetRef 一樣,和 == 相同。
static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); }
從 Object 類的源碼也很容易看出來,equals() 就是直接使用的 == 進(jìn)行判斷的。
public boolean equals(Object obj) { return (this == obj); }
要想使用自己的 equals() 進(jìn)行判斷,就在 targetRef 實(shí)例的類中重寫 equals() 方法。
比如在 User.java 中重寫 equals():
@Override public boolean equals(Object obj) { if(obj == null) return false; else{ if(obj instanceof User){ User user = (User) obj; // String 類已經(jīng)重載了 equals() if(this.name.equals((user).name) && this.age == user.age) return true; else return false; } else return false; } }
使用 or()、isEqual()
package test; import entity.User; import java.util.function.Consumer; import java.util.function.Predicate; public class testPredicate { public static void main(String[] args){ Consumer<User> consumer = user -> user.setName(User.DEFAULT_NAME); Consumer<User> consumer_age = user -> user.setAge(User.DEFAULT_AGE); Predicate<User> predicate = user -> { return user.getName() == null ; }; Predicate<User> predicate_age = user -> { int age = user.getAge(); return (age <= 0 || age >=150); }; User user = new User(); user.setAge(21); if(predicate.or(predicate_age).test(user)) consumer.andThen(consumer_age).accept(user); // if(predicate.and(predicate_age).test(user)) consumer.andThen(consumer_age).accept(user); // if(!predicate.negate().test(user)) consumer.accept(user); // if(predicate.test(user)) consumer.accept(user); User user_equal = new User(User.DEFAULT_AGE , User.DEFAULT_NAME); System.out.println(Predicate.isEqual(user).test(user_equal)); System.out.println(user.equals(user_equal)); System.out.println(user.getName()); System.out.println(user.getAge()); } }
輸出:
true
true
Kaven
20
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決mybatisplus插入報(bào)錯(cuò)argument type mismatch的問題
這篇文章主要介紹了解決mybatisplus插入報(bào)錯(cuò)argument type mismatch的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11springboot的maven多模塊混淆jar包的實(shí)現(xiàn)方法
springboot可以使用proguard-maven-plugin 這個(gè)插件 在 pom.xml 中自定義proguard 的指令,本文基于 springboot + maven + proguard 的maven多模塊架構(gòu)進(jìn)行代碼混淆,需要的朋友可以參考下2024-03-03Spring Security OAuth2集成短信驗(yàn)證碼登錄以及第三方登錄
這篇文章主要介紹了Spring Security OAuth2集成短信驗(yàn)證碼登錄以及第三方登錄,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-04-04使用java實(shí)現(xiàn)各種數(shù)據(jù)統(tǒng)計(jì)圖(柱形圖,餅圖,折線圖)
用Jfree實(shí)現(xiàn)條形柱狀圖表,java代碼實(shí)現(xiàn)??山?jīng)常用于報(bào)表的制作,代碼自動(dòng)生成后可以自由查看??梢宰杂膳渲脠D表的各個(gè)屬性,用來達(dá)到自己的要求和目的。本文給大家介紹使用java實(shí)現(xiàn)各種數(shù)據(jù)統(tǒng)計(jì)圖(柱形圖,餅圖,折線圖),需要的朋友可以參考下2015-10-10Mybatis使用collection標(biāo)簽進(jìn)行樹形結(jié)構(gòu)數(shù)據(jù)查詢時(shí)攜帶外部參數(shù)查詢
這篇文章主要介紹了Mybatis使用collection標(biāo)簽進(jìn)行樹形結(jié)構(gòu)數(shù)據(jù)查詢時(shí)攜帶外部參數(shù)查詢,需要的朋友可以參考下2023-10-10SpringBoot圖文并茂詳解如何引入mybatis與連接Mysql數(shù)據(jù)庫(kù)
這篇文章主要介紹了SpringBoot如何引入mybatis與連接Mysql數(shù)據(jù)庫(kù),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07詳談java編碼互轉(zhuǎn)(application/x-www-form-urlencoded)
下面小編就為大家?guī)硪黄斦刯ava編碼互轉(zhuǎn)(application/x-www-form-urlencoded)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07MyBatis深入解讀動(dòng)態(tài)SQL的實(shí)現(xiàn)
動(dòng)態(tài) SQL 是 MyBatis 的強(qiáng)大特性之一。如果你使用過 JDBC 或其它類似的框架,你應(yīng)該能理解根據(jù)不同條件拼接 SQL 語(yǔ)句有多痛苦,例如拼接時(shí)要確保不能忘記添加必要的空格,還要注意去掉列表最后一個(gè)列名的逗號(hào)。利用動(dòng)態(tài) SQL,可以徹底擺脫這種痛苦2022-04-04基于String不可變字符與StringBuilder可變字符的效率問題
這篇文章主要介紹了String不可變字符與StringBuilder可變字符的效率問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07SpringBoot借助spring.factories文件跨模塊實(shí)例化Bean
這篇文章主要介紹了SpringBoot借助spring.factories文件跨模塊實(shí)例化Bean,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,需要的小伙伴可以參考一下2022-04-04