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 介面是函式式介面,並且這個函式式介面的唯一抽象方法是沒有返回值的,也許大家會有疑惑,沒有返回值,那這個介面有什麼用呢?當然,這個介面不會給我們返回什麼值,但是我們可以用來修改傳遞過來的引數啊,這樣比直接修改又多了什麼優點呢?額,自己挖坑?我也說不上來多了什麼優點,我還很弱,不過我喜歡這種程式設計方式。
直接使用 accept()
舉個例子,假如使用者的 name 為 null,那麼就可以給他設定一個預設的 name ,想不到好的例子,感覺這個例子不是很合理,但是意思差不多。
User.java:
package entity; public class User { // 使用者預設名字 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 進行 accept() 後,after 再進行 accept(),相當於進行了兩次 accept() 。
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
下面以小學成績單為例,假設小學成績單是由兩門單科成績(語文、數學)和總分組成,當我們需要修改其中一門成績的時候,我們是不是也需要修改總分呢?這是肯定的啊。當然,這個例子也不是很合理。
Grade.java:
package entity;
public class Grade {
// 語文成績
private int chinese_language;
// 英語成績
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("英語成績為:%d\n",grade.getEnglish());
System.out.printf("總分為:%d\n",grade.getTotal_score());
english.andThen(total_score).accept(grade);
System.out.println("修改英語成績後---------------");
System.out.printf("英語成績為:%d\n",grade.getEnglish());
System.out.printf("總分為:%d\n",grade.getTotal_score());
}
}
輸出:
英語成績為:70
總分為:150
修改英語成績後---------------
英語成績為:80
總分為: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 介面也是函式式介面,呼叫介面的 test 方法會返回一個布林型別的值,其實從 Predicate 介面的原始碼中也可以看出來,這個介面的用處是什麼。
以我的理解,是可以用來判斷傳遞過來的引數是否匹配一些條件。
使用 test()
我們還是使用 Consumer 介面的例子,當用戶的 name 為 null 時,給使用者設定預設的 name。
我們可以用 Predicate 介面來判斷使用者的 name 是否為空,可能看起來比直接比較麻煩一點。
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() 是返回一個對 test() 的結果取一次反的 Predicate 例項。
default Predicate<T> negate() {
return (t) -> !test(t);
}
也可以這樣用,負負得正不是嗎。
if(!predicate.negate().test(user)) consumer.accept(user);
使用 and()
and() 返回一個對兩個 test() 以 && 的方式的 Predicate 例項。
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
在 User.java 裡面加一個使用者預設年齡屬性。
// 使用者預設年齡
public static final int DEFAULT_AGE = 20;
當用戶年齡不符合情況並且名字為空時,就重新設定使用者的年齡和名字。
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介面還有兩個方法:
or()
or() 方法應該很容易理解,or() 返回一個對兩個 test() 以 || 的方式的 Predicate 例項。
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
isEqual()
介面的靜態方法,看原始碼也很容易理解,生成一個判斷是否與 targetRef equal的 Predicate 例項。targetRef 不為 null 時,如果 targetRef 這個例項的類中沒有過載 Object 類的 equals() 方法或者 targetRef 這個例項本身就是 Object 類的例項,就會使用 Object 類的 equals() 進行判斷,就只會判斷傳遞過來的引數的引用是否與 targetRef 一樣,和 == 相同。
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
從 Object 類的原始碼也很容易看出來,equals() 就是直接使用的 == 進行判斷的。
public boolean equals(Object obj) {
return (this == obj);
}
要想使用自己的 equals() 進行判斷,就在 targetRef 例項的類中重寫 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 類已經過載了 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
要是有說的不對的地方請指正,萬分感謝。