死磕Lambda表达式(四):常用的函数式接口
失去人性,失去很多;失去兽性,失去一切。——《三体》
在java8支持lambda表达式以后,为了满足lambda表达式的一些典型使用场景,jdk为我们提供了大量常用的函数式接口。它们主要在 java.util.function 包中,下面简单介绍几个其中的接口及其使用示例。
supplier接口
supplier
接口是对象实例的提供者,定义了一个名叫get
的抽象方法,它没有任何入参,并返回一个泛型t对象,具体源码如下:
package java.util.function; @functionalinterface public interface supplier<t> { t get(); }
源码比较简单,我们来个例子。这是一个之前提过的表示口罩的类:
package one.more.study; /** * 口罩 */ public class mask { public mask(string brand, string type) { this.brand = brand; this.type = type; } /** * 品牌 */ private string brand; /** * 类型 */ private string type; public string getbrand() { return brand; } public void setbrand(string brand) { this.brand = brand; } public string gettype() { return type; } public void settype(string type) { this.type = type; } }
下面我们使用lambda表达式声明一个supplier
的实例:
supplier<mask> supplier = () -> new mask("3m", "n95");
用它来创建品牌为3m、类型为n95的mask
实例:
mask mask = supplier.get(); system.out.println("brand: " + mask.getbrand() + ", type: " + mask.gettype());
运行结果如下:
brand: 3m, type: n95
特别需要注意的是,本例中每一次调用get
方法都会创建新的对象。
欢迎关注微信公众号:万猫学社,每周一分享java技术干货。
consumer接口
consumer
接口是一个类似消费者的接口,定义了一个名叫accept
的抽象方法,它的入参是一个泛型t对象,没有任何返回(void),主要源码如下:
package java.util.function; @functionalinterface public interface consumer<t> { void accept(t t); }
结合上面的supplier
接口,我们来个例子:
supplier<mask> supplier = () -> new mask("3m", "n95"); consumer<mask> consumer = (mask mask) -> { system.out.println("brand: " + mask.getbrand() + ", type: " + mask.gettype()); }; consumer.accept(supplier.get());
首先使用lambda表达式声明一个supplier
的实例,它是用来创建品牌为3m、类型为n95的mask
实例;再使用lambda表达式声明一个consumer
的实例,它是用于打印出mask
实例的相关信息;最后consumer
消费了supplier
生产的mask
。运行结果如下:
brand: 3m, type: n95
欢迎关注微信公众号:万猫学社,每周一分享java技术干货。
predicate接口
predicate
接口是判断是与否的接口,定义了一个名叫test
的抽象方法,它的入参是一个泛型t对象,并返回一个boolean类型,主要源码如下:
package java.util.function; @functionalinterface public interface predicate<t> { boolean test(t t); }
结合上面的supplier
接口,我们来个例子:
supplier<mask> supplier = () -> new mask("3m", "n95"); predicate<mask> n95 = (mask mask) -> "n95".equals(mask.gettype()); predicate<mask> kn95 = (mask mask) -> "kn95".equals(mask.gettype()); system.out.println("是否为n95口罩:" + n95.test(supplier.get())); system.out.println("是否为kn95口罩:" + kn95.test(supplier.get()));
首先使用lambda表达式声明一个supplier
的实例,它是用来创建品牌为3m、类型为n95的mask
实例;再使用lambda表达式声明一个predicate
的实例n95,它是用于判断是否为n95口罩;再使用lambda表达式声明一个predicate
的实例kn95,它是用于判断是否为kn95口罩;最后分别用两个predicate
判断supplier
生产的mask
。运行结果如下:
是否为n95口罩:true 是否为kn95口罩:false
欢迎关注微信公众号:万猫学社,每周一分享java技术干货。
function接口
function
接口是对实例进行处理转换的接口,定义了一个名叫apply
的抽象方法,它的入参是一个泛型t对象,并返回一个泛型t对象,主要源码如下:
package java.util.function; @functionalinterface public interface function<t, r> { r apply(t t); }
结合上面的supplier
接口,我们来个例子:
supplier<mask> supplier = () -> new mask("3m", "n95"); function<mask, string> brand = (mask mask) -> mask.getbrand(); function<mask, string> type = (mask mask) -> mask.gettype(); system.out.println("口罩品牌:" + brand.apply(supplier.get())); system.out.println("口罩类型:" + type.apply(supplier.get()));
首先使用lambda表达式声明一个supplier
的实例,它是用来创建品牌为3m、类型为n95的mask
实例;再使用lambda表达式声明一个function
的实例brand,它是用于获取口罩的品牌;再使用lambda表达式声明一个function
的实例type,它是用于获取口罩的类型;最后分别用两个function
分析supplier
生产的mask
。运行结果如下:
口罩品牌:3m 口罩类型:n95
欢迎关注微信公众号:万猫学社,每周一分享java技术干货。
bifunction接口
function
接口的入参只有一个泛型对象,jdk还为我们提供了两个泛型对象入参的接口:bifunction
接口,主要源码如下:
package java.util.function; @functionalinterface public interface bifunction<t, u, r> { r apply(t t, u u); }
我们可以用bifunction
接口传入两个string
直接创建mask
实例:
bifunction<string,string,mask> bifunction = (string brand, string type) -> new mask(brand, type); mask mask = bifunction.apply("3m", "n95"); system.out.println("brand: " + mask.getbrand() + ", type: " + mask.gettype());
运行结果如下:
brand: 3m, type: n95
欢迎关注微信公众号:万猫学社,每周一分享java技术干货。
基本数据类型
以上介绍的几个常用的函数式接口入参和返回,都是泛型对象的,也就是必须为引用类型。当我们传入或获取的是基本数据类型时,将会发生自动装箱和自动拆箱,带来不必要的性能损耗,比如:
supplier<long> supplier = () -> system.currenttimemillis(); long timemillis = supplier.get();
在上面例子里,发生了一次自动装箱(long被装箱为long)和一次拆箱(long被拆箱为long),如何避免这种不必要的性能损耗呢?jdk为我们提供相应的函数式接口,如longsupplier
接口,定义了一个名叫getaslong
的抽象方法,签名是() -> long
。上面的例子可以优化为:
longsupplier supplier = () -> system.currenttimemillis(); long timemillis = supplier.getaslong();
类似这样的接口还有很多,我为大家整理了一下:
supplier相关的接口
接口名称 | 方法名称 | 方法签名 |
---|---|---|
supplier | get | () -> t |
booleansupplier | getasboolean | () -> boolean |
doublesupplier | getasdouble | () -> double |
intsupplier | getasint | () -> int |
longsupplier | getaslong | () -> long |
consumer相关的接口
接口名称 | 方法名称 | 方法签名 |
---|---|---|
consumer | accept | (t) -> void |
doubleconsumer | accept | (double) -> void |
intconsumer | accept | (int) -> void |
longconsumer | accept | (long) -> void |
objdoubleconsumer | accept | (t, double) -> void |
objintconsumer | accept | (t, int) -> void |
objlongconsumer | accept | (t, long) -> void |
predicate相关的接口
接口名称 | 方法名称 | 方法签名 |
---|---|---|
predicate | test | (t) -> boolean |
bipredicate | test | (t, u) -> boolean |
doublepredicate | test | (double) -> boolean |
intpredicate | test | (int) -> boolean |
longpredicate | test | (long) -> boolean |
function相关的接口
接口名称 | 方法名称 | 方法签名 |
---|---|---|
function | apply | (t) -> r |
bifunction | apply | (t, u) -> r |
doublefunction | apply | (double) -> r |
doubletointfunction | applyasint | (double) -> int |
doubletolongfunction | applyaslong | (double) -> long |
intfunction | apply | (int) -> r |
inttodoublefunction | applyasdouble | (int) -> double |
inttolongfunction | applyaslong | (int) -> long |
longfunction | apply | (long) -> r |
longtodoublefunction | applyasdouble | (long) -> double |
longtointfunction | applyasint | (long) -> int |
todoublefunction | applyasdouble | (t) -> double |
todoublebifunction | applyasdouble | (t, u) -> double |
tointfunction | applyasint | (t) -> int |
tointbifunction | applyasint | (t, u) -> int |
tolongfunction | applyaslong | (t) -> long |
tolongbifunction | applyaslong | (t, u) -> long |
《死磕lambda表达式》系列
- 死磕lambda表达式(一):初识lambda
- 死磕lambda表达式(二):lambda的使用
- 死磕lambda表达式(三):更简洁的lambda
- 死磕lambda表达式(四):常用的函数式接口
- 死磕lambda表达式(五):comparator复合
- 死磕lambda表达式(六):consumer、predicate、function复合
微信公众号:万猫学社
微信扫描二维码
获得更多java技术干货
推荐阅读
-
死磕Lambda表达式(四):常用的函数式接口
-
荐 Java语言基础之JDK1.8新特性(Lambda表达式、函数式接口、Stream流、新的日期API)
-
荐 【Java】lambda表达式与函数式接口的完美配合
-
如何优雅的将文件转换为字符串(环绕执行模式&行为参数化&函数式接口|Lambda表达式)
-
死磕Lambda表达式(四):常用的函数式接口
-
JDK8新特性03 Lambda表达式03_Java8 内置的四大核心函数式接口
-
【Java 20】Java8的其他新特性 - Lambda表达式、函数式接口、方法引用、构造器引用、数组引用、Stream API、Optional类
-
荐 Java语言基础之JDK1.8新特性(Lambda表达式、函数式接口、Stream流、新的日期API)
-
荐 【Java】lambda表达式与函数式接口的完美配合
-
如何优雅的将文件转换为字符串(环绕执行模式&行为参数化&函数式接口|Lambda表达式)