02-JDK新特性-函数式接口

函数式接口

什么是函数式接口

函数式接口(Functional Interface)就是有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

函数式接口可以被隐式转换为 Lambda 表达式。

我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。

定义一个函数式接口
package demo1;@FunctionalInterface
public interface MyFunInterface {public abstract void show();default void showInit(){}
}

注意:

自定义函数式接口时,@FunctionalInterface是可选的,就算不写这个注解,只要满足函数式接口定义的条件,那么定义的接口依旧是函数式接口。

但是,建议加上该注解。

如何理解函数式接口

Java从诞生日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP)编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,Java不得不做出调整以便支持更加广泛的技术要求,也即Java不但可以支持OOP还可以支持OOF(面向函数编程)
在函数式编程语言当中,函数被当做一等公民对待。

在将函数作为一等公民的编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。 在Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的对象类型——函数式接口。

简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。
所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。

JDK 1.8 之前已有的函数式接口:

java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.nio.file.PathMatcher
java.lang.reflect.InvocationHandler
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener

JDK 1.8 新增加的函数接口:

java.util.function

Java 内置四大核心函数式接口

JAVA8在java.util.function定义了大量的函数式接口,核心函数式接口主要有一下四个:

函数式接口参数类型返回类型用途
Interface SupplierT返回类型为T的对象,包含方法 T get()
Interface ConsumerTvoid对类型为T的对象应用操作,包含方法: void accept(T t)
Interface PredicateTboolean确定类型为T的对象是否满足某约束,并返回boolean值。包含方法: boolean test(T t)
Interface Function<T,R>TR对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t)

Supplier接口

Interface Supplier:包含了一个无参的方法

  • T get():获取结果。

T 是Supplier接口的泛型参数,表示返回结果类型

  • 该方法无需要参数,它会按照某种逻辑(由Lambda表达式实现)返回一个结果
  • Supplier接口也被称为生产接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用,但不传入参数。

声明如下:

@FunctionalInterface
public interface Supplier<T> {T get();
}

T 是Supplier接口的泛型参数,表示返回结果类型

案例1

import java.util.function.Supplier;/*** 理解输出Supplier函数式接口* 以返回一个字符串“123”为例** @author Anna.* @date 2024/4/3 12:37*/
public class SupplierDemo3 {public static void main(String[] args) {// 通过实现Supplier接口调用get()方法实现Supplier<String> stringSupplier = new Supplier<String>() {@Overridepublic String get() {return "123";}};System.out.printf("实现Supplier接口的Supplier:%s%n", stringSupplier);System.out.printf("通过实现Supplier接口调用get()方法实现:%s%n", stringSupplier.get());// 通过函数式接口传入Lambda表达式的方式实现String str = getStringBySupplier(() -> "123");System.out.printf("通过函数式接口传入Lambda表达式的方式实现:%s%n", str);}/*** 定义一个返回类型是String的Supplier接口函数调用方法** @author Anna.* @date 2024/4/3 12:39*/public static String getStringBySupplier(Supplier<String> supplier) {System.out.printf("定义方法中的Supplier:%s%n", supplier);return supplier.get();}
}

执行结果

在这里插入图片描述

理解:

函数式接口关心入参及返回值,执行过程可以看着将Lambda表达作为参数进行传递,具体实现有由Lambda表达式内部方法体完成。

通过上述结果我们可以看出,实现Supplier接口的Supplier是SupplierDemo3实例的一个内部类,而定义方法中的Supplier返回的却是一个Lambda。

案例2

package demo2;import java.util.function.Supplier;/***  使用Supplier<T>定义一个泛型方法,等到一个同类型的返回数据** @author Anna.* @date 2024/4/1 23:57*/
public class SupplierDemo {public static void main(String[] args) {// 匿名内部类方法实现String str = null;str = get(new Supplier<String>() {@Overridepublic String get() {return "Hello".toUpperCase();}});System.out.printf("匿名内部类方法实现:%s%n",str);// Lambda表达式实现str = get(() -> {return "Hello".toUpperCase();});System.out.printf("Lambda表达式实现:%s%n",str);// Lambda表达式简写实现str = get(() -> "Hello".toUpperCase());System.out.printf("Lambda表达式简写实现:%s%n",str);// 方法引用实现str = get("Hello"::toUpperCase);System.out.printf("方法引用实现:%s%n",str);}/*** 定义一个泛型方法,等到一个同类型的返回数据** @param supplier* @return T* @author Anna.* @date 2024/4/2 0:00*/public static <T> T get(Supplier<T> supplier){return supplier.get();}
}

执行结果

在这里插入图片描述

案例3

package demo2;import java.util.function.Supplier;/*** 使用Supplier<T>定义一个泛型方法,获取数组中的最大值** @author Anna.* @date 2024/4/1 23:57*/
public class SupplierDemo2 {public static void main(String[] args) {// 定义一个数组int[] arr = {123, 12, 123, 233, 1231};Integer max = get(() -> {int rtn = 0;for (int item : arr) {if (item > rtn) {rtn = item;}}return rtn;});System.out.println("max = " + max);// 抽取方法max = get(() -> getInteger(arr));System.out.println("max = " + max);}/*** 定义一个泛型方法,等到一个同类型的返回数据** @param supplier* @return T* @author Anna.* @date 2024/4/2 0:00*/public static <T> T get(Supplier<T> supplier) {return supplier.get();}/*** 提取成一个方法** @param arr* @return java.lang.Integer* @author Anna.* @date 2024/4/2 9:22*/private static Integer getInteger(int[] arr) {int rtn = 0;if (arr != null && arr.length > 0) {for (int item : arr) {if (item > rtn) {rtn = item;}}}return rtn;}}

执行结果

在这里插入图片描述

Consumer接口

Interface Consumer:包含两个方法:

  • void accept(T t):对给定的参数执行操作

T 是Consumer接口的泛型参数,表示返回传入参数类型

  • default Consumer andThen(Consumer<? super T> after):Consumer组合依次执行andThen操作,然后执行after操作。

    Consumer接口也被称为消费型接口,它消费的数据类型由泛型指定,不返回任何结果。

案例1

package demo3;import java.util.function.Consumer;/*** String[] strArray = {"张三,数学,30","李四,语文,40","王五,体育,100"};* 字符串数组中包含多条信息,请按照格式,“姓名:XXX,科目:XXX,分数:XXX”的格式将信息打印出来* 要求:* 把打印姓名的动作作为第一个Consumer接口的Lambda示例* 把打印科目的动作作为第二个Consumer接口的Lambda示例* 把打印分数的动作作为第三个Consumer接口的Lambda示例* 将三个Consumer接口按照顺序组合到一起使用** @author Anna.* @date 2024/4/3 12:08*/
public class ConsumerDemo {public static void main(String[] args) {String[] strArray = {"张三,数学,30", "李四,语文,40", "王五,体育,100"};print(strArray,s -> System.out.print("姓名:" + s.split(",")[0] + ","),   // 第一个Consumer接口的Lambdas -> System.out.print("科目:" + s.split(",")[1] + ","),   // 第二个Consumer接口的Lambdas -> System.out.println("分数:" + s.split(",")[2]));     // 第三个Consumer接口的Lambda}public static void print(String[] arr, Consumer<String> com1, Consumer<String> com2, Consumer<String> com3) {for (String str : arr) {// 链式调用 等价于//  com1.accept(str);//  com2.accept(str);//  com3.accept(str);com1.andThen(com2).andThen(com3).accept(str);}}
}

执行结果

在这里插入图片描述

案例2

package demo3;import java.util.function.Consumer;/*** 定义一个Config对象,通过函数式接口,完成数据的初始化** @author Anna.* @date 2024/4/3 12:08*/
public class ConsumerConfig {private String ip;private Integer port;/*** 初始化对象** @param consumer* @return void* @author Anna.* @date 2024/4/3 12:25*/public void init(Consumer<ConsumerConfig> consumer) {consumer.accept(this);}public void setIp(String ip) {this.ip = ip;}public void setPort(Integer port) {this.port = port;}@Overridepublic String toString() {return "ConsumerConfig{" +"ip='" + ip + '\'' +", port=" + port +'}';}public static void main(String[] args) {ConsumerConfig config = new ConsumerConfig();System.out.println("未初始化之前:" + config);config.init((consumer) -> {consumer.setIp("127.0.0.1");consumer.setPort(8080);});System.out.println("初始化之后:" + config);}
}

执行结果

在这里插入图片描述

Predicate接口

Interface Predicate:常用的四个方法:

  • boolean test(T t):对给定的参数进行判断(判断逻辑有Lambda表达式实现),返回一个布尔值

T 是Predicate接口的泛型参数,表示返回传入参数类型

  • default Predicate and(Predicate<? super T> other):返回一个逻辑的否定,对应逻辑非(!),源码如下
default Predicate<T> negate() {return (t) -> !test(t);}
  • default Predicate negate():返回一个组合判断,对应短路与(&&),源码如下
default Predicate<T> and(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) && other.test(t);
}
  • default Predicate or(Predicate<? super T> other):返回一个组合判断,对应逻辑或(||),源码如下
default Predicate<T> or(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) || other.test(t);
}

案例1

package demo4;import java.util.function.Predicate;/*** 使用函数式接口Predicate,完成以下校验* 1 判断一个字符串长度是否大于5* 2 判断一个字符串长度小于5且已S开头* 3 判断一个字符串小于等于5** @author Anna.* @date 2024/4/3 14:10*/
public class PredicateDemo {public static void main(String[] args) {// 判断一个字符串长度是否大于5test01("12321", s -> s != null && s.length() > 5);// 判断一个字符串长度小于5且已S开头test02(null, s -> s != null && s.length() > 5, s -> s.startsWith("S"));// 判断一个字符串小于等于5test03("S2321", s -> s != null && s.length() > 5);}public static void test01(String str, Predicate<String> predicate) {System.out.println(predicate.test(str));}public static void test02(String str, Predicate<String> pdc1, Predicate<String> pdc2) {System.out.println(pdc1.and(pdc2).test(str));}public static void test03(String str, Predicate<String> pdc1) {System.out.println(pdc1.negate().test(str));}
}

执行结果

在这里插入图片描述

Function接口

Interface Function<T,R>:常用的两个方法:

  • R apply(T t):将此函数应用于给定的参数

T,R 是Function接口的泛型参数,T表示返回传入参数类型, R表示返回参数类型

  • default Function<T,V> andThen(Function<? super R,? extends V> after):返回一个组合函数,首先将该函数应用于输出,然后将after函数应用于结果。源码如下:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {Objects.requireNonNull(after);return (T t) -> after.apply(apply(t));
}
  • Function<T,R>接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),并返回一个新的值。

案例1

package demo5;import java.util.function.Function;/*** 使用Function函数式接口:*      1 将一个字符串数字,转换成int类型,输出在控制台*      2 将一个字符串数字,转换成int类型,然后使用第二个Lambda表达式完成,加20,最后输出在控制台* @author Anna.* @date 2024/4/3 14:59*/
public class FunctionDemo {public static void main(String[] args) {// 将一个字符串数字,转换成int类型,输出在控制台print("213", Integer::parseInt);// 将一个字符串数字,转换成int类型,然后使用第二个Lambda表达式完成,加20,最后输出在控制台printAdd("100",Integer::parseInt,s -> s + 20);}public static void print(String str, Function<String,Integer> func){System.out.println(func.apply(str));}public static void printAdd(String str, Function<String,Integer> func1,Function<Integer,Integer> func2){System.out.println(func1.andThen(func2).apply(str));}
}

执行结果

在这里插入图片描述

gitee源码

git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/593724.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

51单片机入门_江协科技_21.2_74HC595 在Proteus中模拟8x8点阵屏环境搭建

1. 为了在proteus中模拟学习江协科技51单片机教程&#xff0c;需要在proteus中搭建74HC595驱动8x8点阵屏的仿真环境&#xff1b; 1.1. 因为连接单片机P0口作为点阵屏负极&#xff08;行选&#xff09;&#xff0c;所以需要先在P0口上接上上拉电阻RESPACK 8&#xff0c;1k欧姆阻…

单细胞RNA测序(scRNA-seq)SRA数据下载及fastq-dumq数据拆分

单细胞RNA测序&#xff08;scRNA-seq&#xff09;入门可查看以下文章&#xff1a; 单细胞RNA测序&#xff08;scRNA-seq&#xff09;工作流程入门 单细胞RNA测序&#xff08;scRNA-seq&#xff09;细胞分离与扩增 1. NCBI查询scRNA-seq SRA数据 NCBI地址&#xff1a; https…

【React】React18+Typescript+craco配置最小化批量引入Svg并应用的组件

React18Typescriptcraco配置最小化批量引入Svg并应用的组件 前言创建React Typescript项目通过require.context实现批量引入Svg安装[types/webpack-env](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.zh-Hans.md)解决类型报错安装[craco](https://…

力扣---旋转链表

给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], k 2 输出&#xff1a;[4,5,1,2,3]示例 2&#xff1a; 输入&#xff1a;head [0,1,2], k 4 输出&#xff1a;[2,0,1…

如何将本地仓库放到远程仓库中

在我们仓库创建好之后&#xff0c;我们复制好ssh 接着我们需要使用git remote add<shortname><url>这个命令 shortname就是我们远程仓库的别名 接着使用git remote -v这个命令查看一下目前远程仓库的别名和地址 原本还有一个指令git branch -M main 指定分支的名…

鸿蒙开发第一课-工具与HelloWorld

武汉数字人才实训基地 一、初始HarmonyOS以及DevEco Studio 2023年8月4日&#xff0c;HarmonyOS 4.0操作系统正式发布。华为鸿蒙Next&#xff08;HarmonyOS Next&#xff09;操作系统开发者预览版(Developer Preview)发布。超过7亿台设备搭载了HarmonyOS 系统 2024年&#xf…

基于java web的超市管理系统

摘要 随着社会经济的不断发展&#xff0c;人们的生活水平不断提高。越来越多的零售行业得到了快速的发展&#xff0c;以最常见的超市最为明显。零售行业繁荣的背后也随之带来了许多行业隐患&#xff0c;越来越激烈的行业竞争不断的要求经营者更加高要求的管理超市内部的整个供…

“医”探究竟 | 骨科检查X光片、CT、核磁共振到底有什么区别?

在门诊经常碰到一些患者搞不清楚 X光、CT、核磁共振这些影像学检查&#xff0c; 到底有什么区别&#xff1f; 用作什么部位检查&#xff1f; 还有&#xff0c; 为什么有时照了X光&#xff0c;还要再做CT&#xff1f; 医生让我做那么昂贵的核磁共振&#xff0c; 莫不是想赚…

如何打包一个手机软件

目录 前言&#xff1a; 准备工具&#xff1a; 创建项目&#xff1a; 打包程序&#xff1a; 前言&#xff1a; 我们平时手机上使用的程序&#xff0c;或者电脑上使用的程序都可以由Web程序打包而来的&#xff0c;而打包不是一个.html文件也不是一个.js文件而是一个大型的文…

【蓝桥杯嵌入式】六、真题演练(二)-1研究篇:第 13 届真题-第二部分

温馨提示&#xff1a; 真题演练分为模拟篇和研究篇。本专栏的主要作用是记录我的备赛过程&#xff0c;我打算先自己做一遍&#xff0c;把遇到的问题和不同之处记录到演练篇&#xff0c;然后再返回来仔细研究一下&#xff0c;找到最佳的解题方法记录到研究篇。题目在&#xff1a…

Python环境搭建—安装Pycharm开发工具

&#x1f947;作者简介&#xff1a;CSDN内容合伙人、新星计划第三季Python赛道Top1 &#x1f525;本文已收录于Python系列专栏&#xff1a; 零基础学Python &#x1f4ac;订阅专栏后可私信博主进入Python学习交流群&#xff0c;进群可领取Python视频教程以及Python相关电子书合…

蓝桥杯备考3

P8196 [传智杯 #4 决赛] 三元组 题目描述 给定一个长度为 n 的数列 a&#xff0c;对于一个有序整数三元组 (i,j,k)&#xff0c;若其满足 1≤i≤j≤k≤n 并且&#xff0c;则我们称这个三元组是「传智的」。 现在请你计算&#xff0c;有多少有序整数三元组是传智的。 输入格式…