JAVA8的java.util.function包

简介: JAVA8的java.util.function包

一 概述

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



相关文章
|
3月前
|
安全 Java API
JAVA并发编程JUC包之CAS原理
在JDK 1.5之后,Java API引入了`java.util.concurrent`包(简称JUC包),提供了多种并发工具类,如原子类`AtomicXX`、线程池`Executors`、信号量`Semaphore`、阻塞队列等。这些工具类简化了并发编程的复杂度。原子类`Atomic`尤其重要,它提供了线程安全的变量更新方法,支持整型、长整型、布尔型、数组及对象属性的原子修改。结合`volatile`关键字,可以实现多线程环境下共享变量的安全修改。
|
4月前
|
安全 Java 调度
解锁Java并发编程高阶技能:深入剖析无锁CAS机制、揭秘魔法类Unsafe、精通原子包Atomic,打造高效并发应用
【8月更文挑战第4天】在Java并发编程中,无锁编程以高性能和低延迟应对高并发挑战。核心在于无锁CAS(Compare-And-Swap)机制,它基于硬件支持,确保原子性更新;Unsafe类提供底层内存操作,实现CAS;原子包java.util.concurrent.atomic封装了CAS操作,简化并发编程。通过`AtomicInteger`示例,展现了线程安全的自增操作,突显了这些技术在构建高效并发程序中的关键作用。
71 1
|
2月前
|
Java 数据处理
|
3月前
|
设计模式 Java
结合HashMap与Java 8的Function和Optional消除ifelse判断
`shigen`是一位致力于记录成长、分享认知和留住感动的博客作者。本文通过具体代码示例探讨了如何优化业务代码中的if-else结构。首先展示了一个典型的if-else处理方法,并指出其弊端;然后引入了策略模式和工厂方法等优化方案,最终利用Java 8的Function和Optional特性简化代码。此外,还提到了其他几种消除if-else的方法,如switch-case、枚举行、SpringBoot的IOC等。一起跟随shigen的脚步,让每一天都有所不同!
38 10
结合HashMap与Java 8的Function和Optional消除ifelse判断
|
2月前
|
Java Apache Maven
Java/Spring项目的包开头为什么是com?
本文介绍了 Maven 项目的初始结构,并详细解释了 Java 包命名惯例中的域名反转规则。通过域名反转(如 `com.example`),可以确保包名的唯一性,避免命名冲突,提高代码的可读性和逻辑分层。文章还讨论了域名反转的好处,包括避免命名冲突、全球唯一性、提高代码可读性和逻辑分层。最后,作者提出了一个关于包名的问题,引发读者思考。
Java/Spring项目的包开头为什么是com?
|
3月前
|
Java API 数据处理
Java 包(package)的作用详解
在 Java 中,包(package)用于组织和管理类与接口,具有多项关键作用:1)系统化组织代码,便于理解和维护;2)提供命名空间,避免类名冲突;3)支持访问控制,如 public、protected、默认和 private,增强封装性;4)提升代码可维护性,实现模块化开发;5)简化导入机制,使代码更简洁;6)促进模块化编程,提高代码重用率;7)管理第三方库,避免命名冲突;8)支持 API 设计,便于功能调用;9)配合自动化构建工具,优化项目管理;10)促进团队协作,明确模块归属。合理运用包能显著提升代码质量和开发效率。
|
3月前
|
Java 数据安全/隐私保护
Java 包(package)的使用详解
Java中的包(`package`)用于组织类和接口,避免类名冲突并控制访问权限,提升代码的可维护性和可重用性。通过`package`关键字定义包,创建相应目录结构即可实现。包可通过`import`语句导入,支持导入具体类或整个包。Java提供多种访问权限修饰符(`public`、`protected`、`default`、`private`),以及丰富的标准库包(如`java.lang`、`java.util`等)。合理的包命名和使用对大型项目的开发至关重要。
|
2月前
|
Java 编译器 API
从Java 8到Java 17,这些新特性让你的代码起飞!
【10月更文挑战第10天】在软件开发领域,Java作为一种历史悠久且广泛使用的编程语言,不断进化以适应新的需求和挑战。从Java 8到Java 17,每一次版本更新都带来了诸多新特性和改进,极大地提升了开发效率和代码质量。今天,我们就来一起探讨这些新特性,看看它们是如何让我们的代码“起飞”的。
152 0
|
4月前
|
Java Maven 数据库
|
4月前
|
JavaScript Java API
Java日志通关(二) - Slf4j+Logback 整合及排包
作者日常在与其他同学合作时,经常发现不合理的日志配置以及五花八门的日志记录方式,后续作者打算在团队内做一次Java日志的分享,本文是整理出的系列文章第二篇。