【Java8新特性】函数式接口

news/2024/4/20 10:47:28/文章来源:https://blog.csdn.net/qq_33399435/article/details/127617548

目录

    • 1. 介绍
      • 1.1 @FunctionInterface注解
      • 1.2 函数式接口的调用
    • 2. 函数式编程
      • 2.1 Lambda的延迟加载技术
      • 2.2 Lambda表达式的使用
    • 3. 常用的函数式接口
      • 3.1 Supplier生产型接口
      • 3.2 Consumer消费型接口
        • 默认方法:andThen
      • 3.3 Predicate条件判断接口
      • 3.4 Function普通函数接口
        • 默认方法:andThen compose()
      • 3.5 Operator 同类型相互转换接口

在这里插入图片描述

1. 介绍

Java中的函数式接口指的是:有且仅有一个抽象方法的接口。(通常接口上方都会有@FunctionInterface注解,用于在编译期发现错误)

Java函数式接口的体现就是Lambda表达式,所有函数式接口都是适用于Lambda表达式使用的接口。

1.1 @FunctionInterface注解

@FunctionalInterface // 表明该类为函数式接口
public interface DoubleSupplier {double getAsDouble();
}

只要在类上加上@FunctionInterface注解,则告诉了编译器该类为函数式接口,只要不符合函数接口的只有一个抽象方法的规范,就会报错。

注意:即使不加@FunctionInterface接口,只有一个抽象方法的类,也能算是函数是接口,只是编译器不知道。

1.2 函数式接口的调用

public class TestFunInterface2 {//需求:使用Consumer接口作为方法的参数,对字符串实现翻转public static void revString(String str, Consumer<String> consumer){consumer.accept(str);}public static void main(String[] args) {revString("zhangsan",(str)->{StringBuilder reverseStr = new StringBuilder(str).reverse();System.out.println("翻转后的字符串:"+reverseStr);});}
}

2. 函数式编程

2.1 Lambda的延迟加载技术

通过log4j的日志打印功能举例:

public class Demo01Logger {private static void log(int level, String msg) {if (level == 1) {System.out.println(msg);}}public static void main(String[] args) {String msgA = "Hello";String msgB = "World";String msgC = "Java";log(1, msgA + msgB + msgC);// 无论是否满足log级别为1,都会执行字符串拼接,造成性能浪费。}
}

经过Lambda表达式的优化后:只有满足日志级别为2,才能进入lambda表达式,进行字符拼接。

@FunctionalInterface
public interface MessageBuilder {String buildMessage();
}
public class Demo02LoggerLambda {private static void log(int level, MessageBuilder builder) {if (level == 1) {// 实际上利用内部类 延迟的原理,代码不相关 无需进入到启动代理执行System.out.println(builder.buildMessage());}}public static void main(String[] args) {String msgA = "Hello";String msgB = "World";String msgC = "Java";log(2,()->{System.out.println("lambda 是否执行了");return msgA + msgB + msgC;});}
}

2.2 Lambda表达式的使用

  1. Lambda表达式作为参数
public class Runnable {private static void startThread(Runnable task) {new Thread(task).start();}public static void main(String[] args) {startThread(()> System.out.println("线程任务执行!"));}
}
  1. Lambda表达式作为返回值
public class lambda_Comparator {private static Comparator<String> newComparator1(){return new Comparator<String>() {@Overridepublic int compare(String a, String b) {return b.length()-a.length();    }};}public static void main(String[] args) {String[] array={"abc","ab","abcd"};Arrays.sort(array, newComparator1()); // 方式一:复杂写法Arrays.sort(array,(a,b)->b.length()-a.length());//更简单的方式System.out.println(Arrays.toString(array));}
}

3. 常用的函数式接口

3.1 Supplier生产型接口

java.util.function.Supplier<T> 接口是生产一个数据,其数据类型由泛型T来定。

Supplier 接口仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定类型的对象数据。

public class Test_Supplier {private static String test_Supplier(Supplier<String> suply) {return suply.get(); //供应者接口}public static void main(String[] args) {// Lambda表达式写法:产生的数据作为 sout 作为输出System.out.println(test_Supplier(()->"产生数据"));// 匿名内部类写法:System.out.println(String.valueOf(new Supplier<String>() {@Overridepublic String get() {return "产生数据";}}));}
}

3.2 Consumer消费型接口

java.util.function.Consumer<T> 接口是消费一个数据,其数据类型由泛型决定。

Consumer 接口中包含抽象方法 void accept(T t) ,表示消费一个指定泛型的数据。基本使用如:

public class Test_Comsumer {public static void generateX(Consumer<String> consumer) {consumer.accept("hello consumer");}public static void main(String[] args) {generateX(s->System.out.println(s));}
}

默认方法:andThen

将两个Consumer组合,先消费一条数据,随后再消费一条数据。

default Consumer<T> andThen(Consumer<? super T> after) {Objects.requireNonNull(after);return (T t)> { accept(t); after.accept(t); }; //1:  返回值为Consumer 那么需要 ()-> 表示函数式接口//2:  accept(t);为生产一个数据供应给 (T t)中的t//3:  after.accept(t);为利用这个t再次生成新的函数式接口 实现类始于builder的设计模式
}

例如:

public class TestFunInterface3 {public static void method(String s, Consumer<String> con1,Consumer<String> con2){//con1.accept(s);//con2.accept(s);con1.andThen(con2).accept(s); //谁在前面谁先消费}public static void main(String[] args) {method("zhangsan",(str)->{System.out.println(str.toUpperCase());},(str)->{System.out.println(str.toLowerCase());});}
}

3.3 Predicate条件判断接口

java.util.function.Predicate<T> 用于对某种类型的数据进行判断,并得到一个boolean值结果。(即是生产者,又是消费者)

抽象方法: boolean test(T t) 用于条件判断的场景:

默认方法: and(与)、or(或)、nagte(取反)

既然是条件判断,就会存在与、或、非三种常见的逻辑关系。

其中将两个 Predicate 条件使用“与”逻辑连接起来实现“并且”的效果时,类始于 Consumer接口 andThen()函数 其他三个雷同

default Predicate<T> and(Predicate<? super T> other) {Objects.requireNonNull(other); return (t)> test(t) && other.test(t);
}

静态方法: isEquals

static <T> Predicate<T> isEqual(Object targetRef) {return (null == targetRef)? Objects::isNull: object -> targetRef.equals(object);
}

举例:

public class Use_Predicate {// 判断字符串是否存在o,即是生产者 又是消费者接口private static void method_test(Predicate<String> predicate) {boolean b = predicate.test("OOM SOF");System.out.println(b);}// 判断字符串是否同时存在o和h private static void method_and(Predicate<String> predicate1,Predicate<String> predicate2) {boolean b = predicate1.and(predicate2).test("OOM SOF");System.out.println(b);}// 判断字符串是否存在o或者h private static void method_or(Predicate<String> predicate1,Predicate<String> predicate2) {boolean b = predicate1.or(predicate2).test("OOM SOF");System.out.println(b);}// 判断字符串是否存在o,结果取反private static void method_negate(Predicate<String> predicate) {boolean b = predicate.negate().test("OOM SOF");System.out.println(b);}public static void main(String[] args) {method_test((s)->s.contains("O"));method_and(s->s.contains("O"), s->s.contains("h"));method_or(s->s.contains("O"), s->s.contains("h"));method_negate(s->s.contains("O"));}
}

3.4 Function普通函数接口

java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。

简单来说就是:将 T 转为 R 返回

	// 将数字转换为String类型private static void numberToString(Function<Number, String> function) {String apply = function.apply(12);System.out.println("转换结果:"+apply);}public static void main(String[] args) {numberToString((s)->String.valueOf(s));}

默认方法:andThen compose()

区别: 执行顺序不同,andThen是调用者先执行,传入的function后执行;compose是传入的function先执行,调用者后执行。

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {Objects.requireNonNull(after);// 先执行调用者,再执行after的apply方法return (T t) -> after.apply(apply(t));
}  
// 这里的V 一个是作为输入值 一个是作为输出值  按照调用的顺序的不同 对于 T V 做输入 输出的顺序也不同 注意看
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {Objects.requireNonNull(before);// 先执行before的apply方法,后执行调用者apply方法return (V v) -> apply(before.apply(v));
}

注意调用的先后顺序:

// 静态方法
private static void method_andThen(Function<Integer, Integer> f1, Function<Integer, Integer> f2) {// andThen:先执行f1,再执行f2Integer apply = f1.andThen(f2).apply(2);System.out.println(apply);
}private static void method_compose(Function<Integer, Integer> f1, Function<Integer, Integer> f2) {// compose:先执行f2,再执行f1Integer apply = f1.compose(f2).apply(2);System.out.println(apply);
}public static void main(String[] args) {method_andThen(s -> s + 1, s -> s = s * 2);//6method_compose(s -> s + 1, s -> s = s * s);//5
}

3.5 Operator 同类型相互转换接口

个人理解: 例如对字符串操作,返回字符串类型。像Stream流中的map方法,但是限定了返回值和参数相同。

BinaryOperator<Integer>andthen() 方法不支持两个函数链接操作 也就是不需要再次 BinaryOperator<Integer> 因为源代码规定不允许使用两次输入。

public static void main(String[] args) {// 单个同类型操作UnaryOperator<String> u_str=(s)->s.split(" ")[0];UnaryOperator<String> u_str1=(s)->s.concat(" ok");String apply = u_str.andThen(u_str1).apply("lambda Ok");String apply1 = u_str.compose(u_str1).apply("lambda Ok");System.out.println(apply);System.out.println(apply1);// 两个同类型操作BinaryOperator<Integer> way_add=(k, v)->k+v;BinaryOperator<Integer> way_mul=(k,v)->k*v;// 注意不能连写!Integer res1 = way_add.apply(1,2);Integer res2 = way_mul.apply(1,2);System.out.println(res1);System.out.println(res2);
}

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

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

相关文章

ASP.NET Core教程-跨域配置(CORS Configuration)

更新记录 转载请注明出处: 2022年11月1日 发布。 2022年11月1日 从笔记迁移到博客。说明 Cross-Origin Resource Sharing,跨域资源共享 配置方式 在ASP.NET Core中有2种方式配置跨越,中间件方式(middleware approach) 和 特性修饰方式(attributes approach)。 中间件方式…

在Jupyter Notebook中使用Matplotlib(Anaconda3)

Matplotlib&#xff08;官网 Matplotlib — Visualization with Python &#xff09;是一个用于创建二维图形的Python库&#xff0c;它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形。将Jupyter Notebook于Matplotlib结合使用效果更好。 在Anaconda3的Jupyter …

HCL AppScan Standard漏洞扫描处理记录

官网&#xff0c;标准版应该是免费的&#xff0c;下载了标准版&#xff0c;没提示激活啥的&#xff0c;最近处理客户的漏洞扫描问题&#xff0c;主要就是修改nginx配置&#xff0c;各种查资料&#xff0c;不停的扫描验证&#xff0c;简单记录下吧。 APP简单使用 app快速下载地…

flutter 系列之:flutter 中的幽灵offstage

文章目录简介Offstage详解Offstage的使用总结简介 我们在使用flutter的过程中&#xff0c;有时候需要控制某些组件是否展示&#xff0c;一种方法是将这个组件从render tree中删除&#xff0c;这样这个组件就相当于没有出现一样&#xff0c;但是有时候&#xff0c;我们只是不想…

技术革新,取代传统会议模式?原来这么简单

随着AI人工智能的盛行&#xff0c;各领域面临前所未有的技术革新。人脸识别作为人工智能的一项重要技术&#xff0c;为工作及生活带来极大便捷&#xff0c;增效赋能。 人脸签到技术5大优势 01.人脸识别稳定&#xff0c;即使在光源不佳、角度受限的环境下也能精准识别&#xff1…

Libuv 各个回调(异步)事件的调用时机

Libuv 各个回调&#xff08;异步&#xff09;事件的调用时机 uv_close、uv_timer_start uv_close中注册的回调事件&#xff08;close_cb&#xff09;查阅官网API文档&#xff0c;Handle句柄是调用uv_close便会立即关闭&#xff0c;而注册的回调事件将推迟到下一次Loop循环中执…

设计模式——创建型模式

五大-创建型模式一、单例模式1、简介2、单例模式八种方式2.1、饿汉式&#xff08;静态常量&#xff09;2.2、饿汉式&#xff08;静态代码块&#xff09;2.3、懒汉式&#xff08;线程不安全&#xff09;2.4、懒汉式&#xff08;线程安全&#xff0c;加同步方法&#xff09;2.5、…

C2 实验 学习笔记

C2 实验 免责声明 本文档仅供学习和研究使用,请勿使用文中的技术源码用于非法用途,任何人造成的任何负面影响,与本人无关. C2隐藏技术 CDN 准备 一台 vultr centos7 机器一个域名cloudflare 账号 挂上 cdn 在域名购买后配置&#xff0c;cf 中的域名解析&#xff0c;在 cf 中配置…

「MySQL高级篇」MySQL之MVCC实现原理事务隔离级别的实现

①MVCC定义,用处,快照读,当前读 ②MVCC实现原理:隐藏字段,readview,undo log ③readview访问规则 ④事务隔离级别的具体实现大家好,我是melo,一名大三后台练习生,死去的MVCC突然开始拷打我🤣🤣🤣!🍳引言 MVCC,非常顺口的一个词,翻译起来却不是特别顺口:多…

Fiddler 抓包工具

1 基本使用 官网下载地址&#xff1a;Download Fiddler Web Debugging Tool for Free by Telerik X.1 电脑端监听 我们双击打开软件&#xff0c;进入到如下的一个界面&#xff0c;然后点击某一个请求&#xff0c;你会发现请求的内容是一堆明显不对的文字&#xff0c;然后该请求…

MySQL性能优化和慢查询日志

目标 了解性能优化的方案能够使用慢日志定位慢SQL 讲解 1. 优化方案 1.1 为什么要优化数据库性能 ​ MySQL凭借着出色的性能、低廉的成本、丰富的资源&#xff0c;已经成为绝大多数互联网公司的首选关系型数据库。可以看到Google&#xff0c;Facebook&#xff0c;Twitter&…

【百度地图】百度地图的使用方法 和 在vue中如何使用百度地图(超详细)

【百度地图】百度地图的使用方法 和 在vue中如何使用百度地图&#xff08;超详细&#xff09; 1- 介绍 百度地图功能强大&#xff0c;本篇文章只是对百度地图JavaScript API 进行一个介绍~ 官方网址 百度地图开放平台LBS&#xff1a;LocationBusinessServer 基于定义位置的商…

Spark 离线开发框架设计与实现

一、背景 随着 Spark 以及其社区的不断发展&#xff0c;Spark 本身技术也在不断成熟&#xff0c;Spark 在技术架构和性能上的优势越来越明显&#xff0c;目前大多数公司在大数据处理中都倾向使用 Spark。Spark 支持多种语言的开发&#xff0c;如 Scala、Java、Sql、Python 等。…

Matlab神经网络函数newff()新旧用法差异

在Matlab R2010a版中,如果要创建一个具有两个隐含层、且神经元数分别为5、3的前向BP网络,使用旧的语法可以这样写:net1 = newff(minmax(P), [5 3 1]); 注意minmax()函数的使用,还有对输出层神经元数(1)的指定。当然也可以采用新的语法,更简洁(请留意差异):net2 = new…

形态分类行为中的气泡佯谬

“假设光归根结底是波&#xff0c;只是给我们以粒子的印象&#xff0c;因为粒子吸收光波的能量是以离散的包的方式。波从源头传播出去像一个越来越大正在膨胀的气泡&#xff0c;到达一个原子时&#xff0c;气泡破裂&#xff0c;波坍缩并把所有的能量集中在一个地方&#xff0c;…

【数字式时间继电器】TR-23 DC110V

系列型号 TR-20数字式时间继电器&#xff1b;TR-21数字式时间继电器&#xff1b; TR-22数字式时间继电器&#xff1b;TR-23数字式时间继电器&#xff1b; TR-24数字式时间继电器&#xff1b;TR-25数字式时间继电器&#xff1b; TR-20D数字式时间继电器&#xff1b;TR-21D数字式…

无刷电机控制基础(3)——FOC矢量控制入门

本节我们讲一些无刷电机FOC矢量控制的入门知识。 1&#xff09;FOC矢量控制的作用 我们前两节讲的无刷电机&#xff08;BLDC&#xff09;&#xff0c;是最简单的结构&#xff0c;当转子匀速转动时&#xff0c;定子内产生的反电动势是梯形波&#xff1b;在驱动无刷电机转动时&a…

你不知道的JavaScript-----强制类型转换

目录 值类型转换 抽象值的操作 JSON 字符串化 ToNumber&#xff1a; 非数字值到数字值 Number(value) ToBoolean: 转换为布尔类型 Boolean(value) 强制类型转换 字符串和数字之间的显式强制类型转换 奇特的~运算符 字位截除 显式解析数字字符串 显式转换为布尔值 隐…

Mybatis查询返回结果类型专题

文章目录一、返回一条信息二、返回List集合三、返回Map集合四、返回多个Map集合五、返回List集合一、返回一条信息 Student selectById(Long id); 不再赘述 二、返回List集合 List< Student> selectAll(); 不再赘述 三、返回Map集合 用map集合去接收返回来的结果 字…

Python-- list(列表)的使用

目录 1.合并两个有序序列构成一个有序列表 2.编写程序判断列表是否为升序 3.输入一个十进制转换为二进制输出 4.将列表中的前p个元素到尾列表 1.合并两个有序序列构成一个有序列表 代码如下&#xff1a; list1 list(eval(input("请输入有序列表list1:"))) list…