一 概述
name | type | description |
---|---|---|
Consumer | Consumer< T > | 接收T對象,不返回值 |
Predicate | Predicate< T > | 接收T對象並返回boolean |
Function | Function< T, R > | 接收T對象,返回R對象 |
Supplier | Supplier< T > | 提供T對象(例如工廠),不接收值 |
UnaryOperator | UnaryOperator< T > | 接收T對象,返回T對象 |
BiConsumer | BiConsumer<T, U> | 接收T對象和U對象,不返回值 |
BiPredicate | BiPredicate<T, U> | 接收T對象和U對象,返回boolean |
BiFunction | BiFunction<T, U, R> | 接收T對象和U對象,返回R對象 |
BinaryOperator | BinaryOperator< T > | 接收兩個T對象,返回T對象 |
參考:https://blog.csdn.net/huo065000/article/details/78964382
二 Consumer
1 作用
- 消費某個對象
2 使用場景
- Iterable接口的forEach方法需要傳入Consumer,大部分集合類都實現了該接口,用於返回Iterator對象進行迭代。
3 設計思想
- 開發者調用ArrayList.forEach時,一般希望自定義遍歷的消費邏輯,比如:輸出日志或者運算處理等。
- 處理邏輯留給使用者,使用靈活多變。
- 多變的邏輯能夠封裝成一個類(實現Consumer接口),將邏輯提取出來。
PASS:Javascript能夠將函數傳遞給另一個函數,這應該算是函數式編程的一個體現,java的function包中的類也是類似的。
public interface Iterable<T> {
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
}
4 DEMO
public class ConsumerTest {
public static void main(String[] args) {
ArrayList<Employee> employees = new ArrayList<>();
String[] prefix = {"A", "B"};
for (int i = 1; i <= 10; i++)
employees.add(new Employee(prefix[i % 2] + i, i * 1000));
employees.forEach(new SalaryConsumer());
employees.forEach(new NameConsumer());
}
static class Employee {
private String name;
private int salary;
public Employee() {
this.salary = 4000;
}
public Employee(String name, int salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
@Override
public String toString() {
return new StringBuilder()
.append("name:").append(name)
.append(",salary:").append(salary)
.toString();
}
}
// 輸出需要交稅的員工
static class SalaryConsumer implements Consumer<Employee> {
@Override
public void accept(Employee employee) {
if (employee.getSalary() > 2000) {
System.out.println(employee.getName() + "要交稅了.");
}
}
}
// 輸出需要名字前綴是‘A’的員工信息
static class NameConsumer implements Consumer<Employee> {
@Override
public void accept(Employee employee) {
if (employee.getName().startsWith("A")) {
System.out.println(employee.getName() + " salary is " + employee.getSalary());
}
}
}
}
三 Predicate
1 作用
- 判斷對象是否符合某個條件
2 使用場景
ArrayList的removeIf(Predicate):刪除符合條件的元素
如果條件硬編碼在ArrayList中,它將提供無數的實現,但是如果讓調用者傳入條件,這樣ArrayList就可以從復雜和無法猜測的業務中解放出來。
3 設計思想
- 提取條件,讓條件從處理邏輯脫離出來,解耦合
4 DEMO
// employee.getSalary() > 2000 提取成一個條件類
class SalaryConsumer implements Consumer<Employee> {
@Override
public void accept(Employee employee) {
// 自行傳入本地的最低交稅工資
if (new SalaryPredicate(2000).test(employee)) {
System.out.println(employee.getName() + "要交稅了.");
}
}
}
class SalaryPredicate implements Predicate<Employee>{
private int tax;
public SalaryPredicate(int tax) {
this.tax = tax;
}
@Override
public boolean test(Employee employee) {
return employee.getSalary() > tax;
}
}
三 Function
1 作用
- 實現一個”一元函數“,即傳入一個值經過函數的計算返回另一個值。
2 使用場景
- V HashMap.computeIfAbsent(K , Function<K, V>) // 簡化代碼,如果指定的鍵尚未與值關聯或與null關聯,使用函數返回值替換。
- <R> Stream<R> map(Function<? super T, ? extends R> mapper); // 轉換流
3 設計思想
- 一元函數的思想,將轉換邏輯提取出來,解耦合
4 DEMO
public static void main(String[] args) {
ArrayList<Employee> employees = new ArrayList<>();
String[] prefix = {"B", "A"};
for (int i = 1; i <= 10; i++)
employees.add(new Employee(prefix[i % 2] + i, i * 1000));
int[] expenses = ListToArray(employees, new EmployeeToExpenses());// 公司對單個員工的支出數組
int[] incomes = ListToArray(employees, new EmployeeToIncome()); // 單個員工的收入數組
System.out.println("社保+公積金+稅=" + (sum(expenses) - sum(incomes)) + "元");
}
private static int[] ListToArray(List<Employee> list, Function<Employee, Integer> function) {
int[] ints = new int[list.size()];
for (int i = 0; i < ints.length; i++)
ints[i] = function.apply(list.get(i));
return ints;
}
private static int sum(int[] salarys) {
int sum = 0;
for (int i = 0; i < salarys.length; i++)
sum += salarys[i];
return sum;
}
// 公司支出
static class EmployeeToExpenses implements Function<Employee, Integer> {
@Override
public Integer apply(Employee employee) {
// 假設公司公積金和社保為工資的20%
return Double.valueOf(employee.getSalary() * (1 + 0.2)).intValue();
}
}
// 員工實際到手工資
static class EmployeeToIncome implements Function<Employee, Integer> {
@Override
public Integer apply(Employee employee) {
// 假設員工薪水 * 80% 為到手工資
return Double.valueOf(employee.getSalary() * (1 - 0.2)).intValue();
}
}
四 Supplier
1 作用
- 創建一個對象(工廠類)
2 使用場景
- Optional.orElseGet(Supplier<? extends T>):當this對象為null,就通過傳入supplier創建一個T返回。
3 設計思想
- 封裝工廠創建對象的邏輯
4 DEMO
public static void main(String[] args) {
// 生成固定工資的員工
Supplier<Employee> supplier = () -> new Employee();
Employee employee1 = supplier.get();
employee1.setName("test1");
Employee employee2 = supplier.get();
employee2.setName("test2");
System.out.println("employee1:" + employee1);
System.out.println("employee2:" + employee2);
}
五 UnaryOperator
1 作用
- UnaryOperator繼承了Function,與Function作用相同
- 不過UnaryOperator,限定了傳入類型和返回類型必需相同
2 使用場景
- List.replaceAll(UnaryOperator) // 該列表的所有元素替換為運算結算元素
- Stream.iterate(T,UnaryOperator) // 重復對seed調用UnaryOperator來生成元素
3 設計思想
- 一元函數的思想,將同類轉換邏輯提取出來,解耦合
4 DEMO
public static void main(String[] args) {
ArrayList<Employee> employees = new ArrayList<>();
String[] prefix = {"B", "A"};
for (int i = 1; i <= 10; i++)
employees.add(new Employee(prefix[i % 2] + i, i * 1000));
System.o
ut.println("公司進行薪資調整...");
salaryAdjustment(employees,new SalaryAdjustment(4000));
employees.forEach(System.out::println);
}
static void salaryAdjustment(List<Employee> list, UnaryOperator<Employee> operator) {
for (int i = 0; i < list.size(); i++) {
list.set(i, operator.apply(list.get(i)));
}
}
static class SalaryAdjustment implements UnaryOperator<Employee> {
private int salary;
public SalaryAdjustment(int salary) {
this.salary = salary;
}
@Override
public Employee apply(Employee employee) {
employee.setSalary(salary);
return employee;
}
}