01-详细介绍函数式接口和Lambda表达式语法

函数式接口介绍

如果在一个接口中只声明了一个抽象方法,则此接口就被称为函数式接口(该接口可以包含其他非抽象方法)

  • 接口上使用@FunctionalInterface注解可以验证该接口是否为函数式接口,javadoc生成的文档时也会保留该注解, 若接口中有多个抽象方法编译器会报错

随着Python,Scala等语言的兴起和新技术的挑战,Java不得不做出调整以便支持更加广泛的技术要求,所以Java8不但可以支持OOP还可以支持OOF(面向函数编程)

  • 面向对象编程思想:完成一件事情需要找一个能解决这个事情的对象然后调用对象的方法
  • 函数式编程思想: 重视结果不重视过程,只要能获取到结果即可,无论谁去做又怎么做
  • 在函数式编程语言当中Lambda表达式的类型是函数,但在Java8中Lambda表达式是对象而不是函数,它们必须依附于函数式接口

Java内置函数式接口

java.util.function包下定义了Java8的丰富的函数式接口

四大核心函数式接口

函数式接口称谓参数类型用途
Consumer<T> 消费型接口T对类型为T的对象应用操作,包含方法 void accept(T t)
Supplier<T> 供给型接口返回类型为T的对象,包含方法T get()
Function<T, R> 函数型接口T对类型为T的对象应用操作并返回结果R类型的对象,包含方法R apply(T t)
Predicate<T> 判断型接口T确定类型为T的对象是否满足某约束并返回 boolean 值,包含方法boolean test(T t)

消费型接口: 抽象方法有形参但是返回值类型是void

接口名抽象方法描述
BiConsumer<T,U>void accept(T t, U u)接收两个对象用于完成功能
DoubleConsumervoid accept(double value)接收一个double值
IntConsumervoid accept(int value)接收一个int值
LongConsumervoid accept(long value)接收一个long值
ObjDoubleConsumervoid accept(T t, double value)接收一个对象和一个double值
ObjIntConsumervoid accept(T t, int value)接收一个对象和一个int值
ObjLongConsumervoid accept(T t, long value)接收一个对象和一个long值

供给型接口: 抽象方法无参但是有返回值

接口名抽象方法描述
BooleanSupplierboolean getAsBoolean()返回一个boolean值
DoubleSupplierdouble getAsDouble()返回一个double值
IntSupplierint getAsInt()返回一个int值
LongSupplierlong getAsLong()返回一个long值

函数型接口: 抽象方法既有参数又有返回值

接口名抽象方法描述
UnaryOperatorT apply(T t)接收一个T类型对象,返回一个T类型对象结果
DoubleFunctionR apply(double value)接收一个double值,返回一个R类型对象
IntFunctionR apply(int value)接收一个int值,返回一个R类型对象
LongFunctionR apply(long value)接收一个long值,返回一个R类型对象
ToDoubleFunctiondouble applyAsDouble(T value)接收一个T类型对象,返回一个double
ToIntFunctionint applyAsInt(T value)接收一个T类型对象,返回一个int
ToLongFunctionlong applyAsLong(T value)接收一个T类型对象,返回一个long
DoubleToIntFunctionint applyAsInt(double value)接收一个double值,返回一个int结果
DoubleToLongFunctionlong applyAsLong(double value)接收一个double值,返回一个long结果
IntToDoubleFunctiondouble applyAsDouble(int value)接收一个int值,返回一个double结果
IntToLongFunctionlong applyAsLong(int value)接收一个int值,返回一个long结果
LongToDoubleFunctiondouble applyAsDouble(long value)接收一个long值,返回一个double结果
LongToIntFunctionint applyAsInt(long value)接收一个long值,返回一个int结果
DoubleUnaryOperatordouble applyAsDouble(double operand)接收一个double值,返回一个double
IntUnaryOperatorint applyAsInt(int operand)接收一个int值,返回一个int结果
LongUnaryOperatorlong applyAsLong(long operand)接收一个long值,返回一个long结果
BiFunction<T,U,R>R apply(T t, U u)接收一个T类型和一个U类型对象,返回一个R类型对象结果
BinaryOperatorT apply(T t, T u)接收两个T类型对象,返回一个T类型对象结果
ToDoubleBiFunction<T,U>double applyAsDouble(T t, U u)接收一个T类型和一个U类型对象,返回一个double
ToIntBiFunction<T,U>int applyAsInt(T t, U u)接收一个T类型和一个U类型对象,返回一个int
ToLongBiFunction<T,U>long applyAsLong(T t, U u)接收一个T类型和一个U类型对象,返回一个long
DoubleBinaryOperatordouble applyAsDouble(double left, double right)接收两个double值,返回一个double结果
IntBinaryOperatorint applyAsInt(int left, int right)接收两个int值,返回一个int结果
LongBinaryOperatorlong applyAsLong(long left, long right)接收两个long值,返回一个long结果

判断型接口: 抽象方法特点有参但是返回值类型是boolean结果

接口名抽象方法描述
BiPredicate<T,U>boolean test(T t, U u)接收两个对象
DoublePredicateboolean test(double value)接收一个double值
IntPredicateboolean test(int value)接收一个int值
LongPredicateboolean test(long value)接收一个long值

接口的使用

消费型接口使用举例

// 消费性接口
public interface Consumer<Double>{void accept (Double money);
}public void happyTime(double money, Consumer<Double> consumer) {// 调用消费型接口的方法consumer.accept(money);
}
@Test
public void test04() {// 传统写法happyTime(1241, new Consumer<Double>() {@Overridepublic void accept(Double money) {System.out.println("突然想回一趟成都了,机票花费" + money);}});System.out.println("------------------------");// Lambda表达式happyTime(648, money -> System.out.println("学习太累了,奖励自己一发十连,花费" + money));
}

断定型接口使用举例: 根据Predicate接口实现类的实现方法给定的规则,过滤集合中的字符串

public List<String> filterString(List<String> strings, Predicate<String> predicate) {ArrayList<String> res = new ArrayList<>();for (String string : strings) {if (predicate.test(string))res.add(string);}return res;
}@Test
public void test05() {List<String> strings = Arrays.asList("东京", "西京", "南京", "北京", "天津", "中京");// 传统写法List<String> list = filterString(strings, new Predicate<String>() {@Overridepublic boolean test(String s) {return s.contains("京");}});System.out.println(list);System.out.println("------------------------");// Lambda表达式List<String> res = filterString(strings, s -> s.contains("京"));System.out.println(res);
}

Lambda表达式语法的使用

匿名内部类

当需要启动一个线程去完成任务时,通常会通过java.lang.Runnable接口来定义任务内容并使用java.lang.Thread类来启动该线程

  • Thread类需要Runnable接口作为参数,其中的抽象run方法是用来指定线程任务内容的核心
  • 为了指定run的方法体需要创建Runnable接口的实现类,为了省去定义一个RunnableImpl实现类的麻烦需要使用匿名内部类
  • 编写的匿名内部类必须覆盖重写抽象run方法,所以方法名称、方法参数、方法返回值都需要再写一遍且不能写错, 而实际上只有方法体才是关键所在
public class UseFunctionalProgramming {public static void main(String[] args) {// new 接口(){实现类}new Thread(new Runnable() {@Overridepublic void run() {System.out.println("多线程任务执行!");}}).start(); // 启动线程}
}

Lambda表达式的6种形式

我们可以通过Lambda表达式创建函数式接口的实现类对象代替匿名实现类,Lambda表达式是用来简化函数式接口的变量或形参赋值的语法

  • 因为函数式接口只有一个抽象方法,所以我们才可以省略方法名称,方法参数,方法返回值,@Override函数声明等内容
new Thread(() -> {System.out.println("多线程任务执行!");
}).start(); 

Lambda表达式的语法格式如(o1,o2) -> Integer.compare(o1,o2)

  • ->:lambda操作符或箭头操作符
  • ->左边(函数式接口中抽象方法的形参列表):因为有类型推断机制形参的数据类型都可以省略,如果只有一个参数,参数的小括号可以省略
  • ->右边{函数式接口中抽象方法的方法体}: 当Lambda体只有一条语句时(return语句或其他语句),如果是return语句return与{}需要一起省略, 不能只省略{}return不能单独出现

语法格式一: 函数式接口的抽象方法无参无返回值

@Test
public void test01(){// 传统写法Runnable runnable01 = new Runnable() {@Overridepublic void run() {System.out.println("你 的 城 市 好 像 不 欢 迎 我");}};runnable01.run();System.out.println("-------------------------");// Lambda表达式Runnable runnable02 = () -> {System.out.println("所 以 我 只 好 转 身 离 开 了");};runnable02.run();
}

语法格式二: 函数式接口的抽象方法有一个参数但是没有返回值

@Test
public void test03(){//1. 传统写法Consumer<String> consumer01 = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}};consumer01.accept("其实我存过你照片 也研究过你的星座");System.out.println("-------------------------");// Lambda表达式Consumer<String> consumer02 = (String s) -> {System.out.println(s);};consumer02.accept("你喜欢的歌我也会去听 你喜欢的事物我也会想去了解");
}

语法格式三: 函数式接口抽象方法中形参列表的数据类型可以省略,编译器可由类型推断机制得出,底层是由声明变量的泛型类型推断得出

在这里插入图片描述

@Test
public void test() {//类型推断机制1ArrayList<String> list = new ArrayList<>();//类型推断机制2int[] arr = {1, 2, 3};}
@Test
public void test04(){// 传统写法Consumer<String> consumer01 = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}};consumer01.accept("我远比表面上更喜欢你");System.out.println("-------------------------");// Lambda表达式Consumer<String> consumer02 = (s) -> {System.out.println(s);};consumer02.accept("但我没有说");
}

语法格式四: 函数式接口的抽象方法只有一个参数,参数的小括号可以省略

@Test
public void test04(){// 传统写法Consumer<String> consumer01 = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}};consumer01.accept("我远比表面上更喜欢你");System.out.println("-------------------------");// Lambda表达式Consumer<String> consumer02 = s -> {System.out.println(s);};consumer02.accept("但我没有说");
}

语法格式五: 函数式接口的抽象方法有两个或以上参数,方法有返回值,方法体有多条执行语句

@Test
public void test02() {// 传统的写法Comparator<Integer> comparator01 = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {System.out.println(o1);System.out.println(o2);return o1.compareTo(o2);}};System.out.println(comparator01.compare(95, 27));System.out.println("-------------------------");// Lambda表达式Comparator<Integer> comparator02 = (o1, o2) -> {System.out.println(o1);System.out.println(o2);return o1.compareTo(o2);};System.out.println(comparator02.compare(12, 21));
}

语法格式六: 当Lambda体只有一条语句时(可能是return语句),如果是return语句return与{}需要一起省略, 注意不能只省略{}return不能单独出现

public void test02() {// 传统写法Comparator<Integer> comparator01 = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1.compareTo(o2);}};System.out.println(comparator01.compare(95, 27));System.out.println("-------------------------");// Lambda表达式Comparator<Integer> comparator02 = (o1, o2) -> o1.compareTo(o2);System.out.println(comparator02.compare(12, 21));
}

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

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

相关文章

OpenHarmony之NAPI框架介绍

张志成 诚迈科技高级技术专家 NAPI是什么 NAPI的概念源自Nodejs&#xff0c;为了实现javascript脚本与C库之间的相互调用&#xff0c;Nodejs对V8引擎的api做了一层封装&#xff0c;称为NAPI。可以在Nodejs官网&#xff08;https://nodejs.org/dist/latest-v20.x/docs/api/n-api…

利用企业被执行人信息查询API保障商业交易安全

前言 在当今竞争激烈的商业环境中&#xff0c;企业为了保障商业交易的安全性不断寻求新的手段。随着技术的发展&#xff0c;利用企业被执行人信息查询API已经成为了一种强有力的工具&#xff0c;能够帮助企业在商业交易中降低风险&#xff0c;提高合作的信任度。 企业被执行人…

小红书达人类型特点有哪些,创作形式总结!

小红书自带的社交电商属性&#xff0c;吸引了众多优秀的内容创作者和品牌达人。他们以不同的风格和主题&#xff0c;赢得了粉丝们的喜爱和关注。今天为大家分享下小红书达人类型特点有哪些&#xff0c;创作形式总结&#xff01; 1. 内容创作风格 我们从内容上来区分小红书达人类…

关闭vscode打开的本地服务器端口

vscode开了本地的一个端口“8443”当本地服务器端口&#xff0c;然后随手把VScode一关&#xff0c;后来继续做发现8443端口已经被占用了。   原来&#xff0c;即便关闭了编译器VScode&#xff0c;服务器依然是被node.exe运行着的。那这个端口怎么才能关掉呢&#xff1f;   …

css图片缩放属性object-fit说明

object-fit 属性可以设置以下值&#xff1a; 属性值说明例子fill填充容器&#xff0c;可能会改变图片的比例。object-fit: fill;contain保持图片的原始比例&#xff0c;确保图片完全包含在容器内。object-fit: contain;cover保持图片的原始比例&#xff0c;确保图片覆盖整个容…

UML建模图文详解教程04——对象图

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl本文参考资料&#xff1a;《UML面向对象分析、建模与设计&#xff08;第2版&#xff09;》吕云翔&#xff0c;赵天宇 著 对象图 对象图(object diagram)显示了某一时刻的一组…

chatGPT4机器学习数据后最终保留在机器里的是什么? 机器是怎么产生智能的? TensorFlow没有直接开发出类似GPT-4这样的模型

机器学习数据后最终保留在机器里的是机器学习模型。机器学习模型是机器学习系统中的核心&#xff0c;它是机器学习系统能够进行推理和预测的基础。 机器学习模型通常由参数组成。参数是机器学习模型的权重和偏差。机器学习系统通过训练来学习这些参数。训练是指让机器学习系统…

【开源】基于Vue.js的民宿预定管理系统

项目编号&#xff1a; S 058 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S058&#xff0c;文末获取源码。} 项目编号&#xff1a;S058&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用例设计2.2 功能设计2.2.1 租客角色…

Mobaxterm 使用lrzsz传输文件(rz/sz)

Mobaxterm 使用lrzsz传输文件报错 1. 现象 最近从xshell切换到Mobaxterm其他一切正常,就是使用rz传输文件时会出现错误,比较苦恼. 会出现以下错误 [rootcentos7 rpmbuild]# rz ▒CCCCCCCCCCC23be50ive.**B0100000023be502. 解决方法 去官网(https://mobaxterm.mobatek.net…

Map使用数字类型作为key的坑

用什么存的一定要用什么类型取出来&#xff0c;他哪个get是Object类型的&#xff0c;即使你放错了类型也不给你提醒&#xff0c;有点无语。

基于C#实现Kruskal算法

这篇我们看看第二种生成树的 Kruskal 算法&#xff0c;这个算法的魅力在于我们可以打一下算法和数据结构的组合拳&#xff0c;很有意思的。 一、思想 若存在 M{0,1,2,3,4,5}这样 6 个节点&#xff0c;我们知道 Prim 算法构建生成树是从”顶点”这个角度来思考的&#xff0c;然…

CentOS7安装Docker运行环境

1 引言 Docker 是一个用于开发&#xff0c;交付和运行应用程序的开放平台。Docker 使您能够将应用程序与基础架构分开&#xff0c;从而可以快速交付软件。借助 Docker&#xff0c;您可以与管理应用程序相同的方式来管理基础架构。通过利用 Docker 的方法来快速交付&#xff0c;…