基本概述
jdk1.8内置了许多函数式接口供以使用, 都放在java.util.function包下, 常用的基本上是Consumer、Supplier、Function和Predicate四个函数式接口, 其余也并无太大区别
| 接口名 | 抽象方法 | 功能描述 |
|---|---|---|
| Consumer | void accpet(T t) | 消费型接口:将传递进来的对象t作为消费对象,对其进行逻辑处理 |
| Supplier | T get() | 生产型接口:通过对一个无参方法返回一个实例对象 |
| Function | R apply(T t) | 函数型接口:对T类型的对象进行逻辑处理,转换成为R类型(其他类型)返回 |
| Predicate | boolean test(T t ) | 断言型接口:对参数传的对象进行逻辑判断,返回一个boolean类型的判断结果 |
1、Consume:消费型接口
将传递进来的参数对象作为消费对象, 对其进行逻辑处理
String food = "肉";
// 在调用eat()方法时用lambda表达式写出Consumer的消费逻辑
eat(food, s -> {
if (s.equals("肉")) {
System.out.println("今天开荤了!");
}
if (s.equals("菜")) {
System.out.println("今天又是斋戒的一天!");
}
});
}
// 提供一个参数中有Consumer类型的方法
public static <T> void eat(T t, Consumer<T> consumer) {
consumer.accept(t);
}
}
使用场景:遍历集合
集合Collection接口继承了一个迭代器接口Iterable, 而Iterable接口中提供了一个用于遍历集合的forEach方法, 方法参数就是Consumer接口, 截图如下:
List<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
list.add("孙七");
// 遍历List集合
list.forEach(name -> System.out.println(name));
//集合中forEach的源码
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
2、Supplier:生产型接口
通过一个无参方法返回一个实例
// 在调用getString()方法时写出Supplier的生产逻辑
String string = getString(() -> "我是生产出来的String类型的对象");
System.out.println(string); //我是生产出来的String类型的对象
}
// 提供一个参数中有Supplier类型的方法
public static String getString(Supplier<String> supplier) {
String s = supplier.get();
return s;
}
使用场景:Objects.requireNonNull()对象为空时提供空指针异常的错误信息 jdk提供的对象操作工具类Objects中有一个requireNonNull()方法, 该方法的作用是用于判断对象是否为空, 如果为空, 则抛出一个空指针异常, 并指定异常信息,
public static <T> T requireNonNull(T obj, String message) {
if (obj == null)
throw new NullPointerException(message);
return obj;
}
String b=null;
String s = Objects.requireNonNull(b,()->"你给的数据是空的");
System.out.println(s);
//Exception in thread "main" java.lang.NullPointerException: 你给的数据是空的
3、Function:函数型接口
对T类型的对象进行逻辑处理,转换成为R类型(其他类型)的对象
String str=getString(99,i->i.toString());
System.out.println(str+111); //99111
}
public static String getString(Integer integer,Function<Integer,String> function){
String apply=function.apply(integer);
return apply;
}
应用场景: Optional中通过map()方法转换元素类型
jdk1.8提供的专为空指针判断而诞生的一个工具类Optional中, 存在一个map()方法, 用于转换Optional中的元素类型, map方法中的其中一个参数就是Function
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
} //源码
}
基本用法:
// 根据id查询学生对象
Student student = getStuById(123456);
// map方法将元素换为另一种类型的元素(此处将Student类型转换为Boolean类型)
Optional<Boolean> optional = Optional.ofNullable(student).map(stu -> {
if (stu.getName().equals("张三")) {
return true;
} else {
return false;
}
});
}
对于Option类的使用可以参考我的这篇文章,直接速解疑惑JDK8新特性-Optional类 - 掘金 (juejin.cn)
4、Predicate:断言型接口
对参数传的对象进行逻辑判断, 返回一个boolean类型的判断结果
// 如果传入的字符串是西瓜, 就返回true, 不是西瓜就false
boolean pre = predicateTest("苹果", s -> "西瓜".equals(s));
System.out.println(pre);
}
// 提供一个参数中有Predicate类型的方法
public static boolean predicateTest(String s, Predicate<String> predicate) {
return predicate.test(s);
}
}
应用场景:Collection集合中的满足条件就删除元素的方法
集合Collection接口中存在一个removeIf()方法,方法作用就是将集合中的元素按照指定的判断规则移除,参数就是Predicate接口;
//源码
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
//判断是否符合给定的判断规则的要求,满足就直接移除
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
基本使用:
List<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
list.add("张三2");
list.add("张三3");
list.add("张三4");
// 如果存在以"张三"开头的元素, 则从元素中移除
list.removeIf(name -> name.startsWith("张三"));
// 遍历List集合
list.forEach(name -> System.out.println(name));
// 李四
// 王五
// 赵六
总结
函数式接口在代码中运用非常广泛,特别是在Stream或者Optional类中使用时最多的,在配合Lambda表达式,可以让我们在实际开发中的代码更加简洁优雅。最常见的函数式接口几乎就是本文中提到的四种,虽然不止这些,但是处处都是这几个函数,掌握这几个函数后可以如履平地。