前言
通过上一章「Lambda必知必会的基础知识」我们自定义了函数式接口以及使用,相信大家对Lambda有了一定的认识。事实上在实际项目开发中我们很少会自定义函数式接口,因为Java本身为我们内置的函数接口基本上够我们日常开发使用。本章我们要学习Java内置的、常用的函数式接口。
内置函数式接口及使用
函数式接口源码详见java.util.function包
Supplier
生产接口:不接受参数,返回一个<T>
类型的值!适合创建对象,演示如下:
public void testSupplier(){
Supplier<Fruit> supplier = () -> new Banana();
System.out.println(supplier.get());//com.uucoding.java.entity.Banana@11438d26
}
Consumer
消费接口:接受一个<T>
类型参数,无返回值!适合访问一个数据,并对其执行一些操作,演示如下:
public void testConsumer(){
Consumer<String> consumer = val -> System.out.println(val);
consumer.accept("Consumer hello word"); // "Consumer hello word"
}
Predicate
布尔接口:接受一个<T>
类型参数,并返回true / false!适合对T类型数据操作后返回布尔值,演示如下:
public void testPredicate(){
Predicate<String> predicate = (str) -> Objects.nonNull(str);
System.out.println(predicate.test("100")); // true
}
Function
函数接口:接受一个<T>
类型参数,并返回一个<R>
类型的值!适合处理入参,并返回处理结果,演示如下:
public void testFunction(){
Function<String, Integer> function = (str2Int) -> Integer.valueOf(str2Int);
System.out.println(function.apply("100")); // 100
}
BiFunction
增强函数接口:接受<T>
、<U>
类型的两个参数,并返回一个<R>
类型的值,演示如下:
public void testBiFunction(){
BiFunction<Integer, Integer, String> biFunction = (a, b) -> String.valueOf(a + b);
System.out.println(biFunction.apply(1, 2)); // "3"
}
以上五个函数接口是我在工作中经常使用的,你们呢?
内置接口中有的还包含一些默认方法的实现,大家有兴趣的可以看一看,这些默认方法本质上还是通过Lambda的形式对某些关联函数接口进行组合或做一些简化操作。
类型特化
我们知道Java存在装箱和拆箱(由Java自动完成),即将基本类型(int、long等)转化为引用类型(Interger、Long等)称之装箱(本质就是将原始类型包装并保存在堆中,装箱后需要更多的内存) ,反之则为拆箱。如下代码:
public void testQuoteType(){
Consumer<Long> consumer = (val) -> System.out.println(val);
consumer.accept(10L); // 10
}
泛型接口的类型只能绑定引用类型,上述代码中long自动被装箱成Long,这个在性能方面是需要付出一定代价的。Java在java.util.function包中为我们提供针对原始类型的函数式接口,如:LongConsumer
、LongFunction
、LongPredicate
、LongSupplier
等,上述代码可以优化成如下形式:
public void testLongConsumer(){
LongConsumer consumer = (val) -> System.out.println(val);
consumer.accept(10L); // 10
}
基本类型使用种特化的接口可以避免装箱拆箱的操作,从而提高性能!
总结
- 本章主要针对Java内置的接口进行讲解及案例编写;
- 为了避免装箱,当泛型是基本类型的时候请尽可能的使用内置的特化函数式接口;
- 尽量直接使用Java内置的函数式接口,除非这些接口都不满足。