java.util.function包(jdk8新特性)

一 概述

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對象

二 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;
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章