基于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ù)式接口的唯一抽象方法是沒(méi)有返回值的,也許大家會(huì)有疑惑,沒(méi)有返回值,那這個(gè)接口有什么用呢?當(dāng)然,這個(gè)接口不會(huì)給我們返回什么值,但是我們可以用來(lái)修改傳遞過(guò)來(lái)的參數(shù)啊,這樣比直接修改又多了什么優(yōu)點(diǎn)呢?額,自己挖坑?我也說(shuō)不上來(lái)多了什么優(yōu)點(diǎn),我還很弱,不過(guò)我喜歡這種編程方式。
直接使用 accept()
舉個(gè)例子,假如用戶的 name 為 null,那么就可以給他設(shè)置一個(gè)默認(rèn)的 name ,想不到好的例子,感覺(jué)這個(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 接口的源碼中也可以看出來(lái),這個(gè)接口的用處是什么。
以我的理解,是可以用來(lái)判斷傳遞過(guò)來(lái)的參數(shù)是否匹配一些條件。
使用 test()
我們還是使用 Consumer 接口的例子,當(dāng)用戶的 name 為 null 時(shí),給用戶設(shè)置默認(rèn)的 name。
我們可以用 Predicate 接口來(lái)判斷用戶的 name 是否為空,可能看起來(lái)比直接比較麻煩一點(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í)例的類中沒(méi)有重載 Object 類的 equals() 方法或者 targetRef 這個(gè)實(shí)例本身就是 Object 類的實(shí)例,就會(huì)使用 Object 類的 equals() 進(jìn)行判斷,就只會(huì)判斷傳遞過(guò)來(lái)的參數(shù)的引用是否與 targetRef 一樣,和 == 相同。
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
從 Object 類的源碼也很容易看出來(lái),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)文章
圖文詳解java反射機(jī)制及常用應(yīng)用場(chǎng)景
這篇文章主要為大家介紹了圖文詳解java反射機(jī)制及常用應(yīng)用場(chǎng)景,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
SpringBoot中的yaml語(yǔ)法及靜態(tài)資源訪問(wèn)問(wèn)題
這篇文章主要介紹了SpringBoot中的yaml語(yǔ)法及靜態(tài)資源訪問(wèn)問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07
Java 利用DeferredResult實(shí)現(xiàn)http輪詢實(shí)時(shí)返回?cái)?shù)據(jù)接口
這篇文章主要介紹了Java 利用 DeferredResult 實(shí)現(xiàn) http 輪詢實(shí)時(shí)返回?cái)?shù)據(jù)接口,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下2021-03-03
Spring Data Envers支持有條件變動(dòng)紀(jì)錄的保存和查詢的方法
通過(guò)spring-data-envers可以很容易的實(shí)現(xiàn)數(shù)據(jù)變動(dòng)紀(jì)錄的保存和查詢,本文介紹支持有條件變動(dòng)紀(jì)錄的保存和查詢的方法,通過(guò)spring-data-envers很容易的實(shí)現(xiàn)變動(dòng)紀(jì)錄的保存和查詢,只需要增加幾個(gè)注解就可以,感興趣的朋友跟隨小編一起看看吧2023-10-10
使用ShardingSphere-Proxy實(shí)現(xiàn)分表分庫(kù)
這篇文章介紹了使用ShardingSphere-Proxy實(shí)現(xiàn)分表分庫(kù)的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-02-02
JavaMail實(shí)現(xiàn)郵件發(fā)送的方法
這篇文章主要介紹了JavaMail實(shí)現(xiàn)郵件發(fā)送的方法,實(shí)例分析了java實(shí)現(xiàn)郵件發(fā)送的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04
基于servlet的執(zhí)行原理與生命周期(全面解析)
下面小編就為大家分享一篇servlet的執(zhí)行原理與生命周期全面解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12

