盘点java8 stream中隐藏的函数式接口

shigen坚持更新文章的博客写手,记录成长,分享认知,留住感动。个人IP:shigen

提到函数式接口,最常见的就是lambda表达式,IDEA也有智能的提示:

idea智能提示

最后改成这样的就是最简洁的、IDEA希望的风格:

List<String> nameList = users.stream().map(User::getName).collect(Collectors.toList());
log.info("nameList:{}", nameList);

直接一行搞定比较复杂的功能。今天要讲到的函数式接口就从这个展开。

1. 函数式接口

所谓的函数式接口指的是只定义一个抽象方法的接口。接口类常用这个注解@FunctionalInterface表明:

  • java.util.Comparator
public interface Comparator<T> {int compare(T o1, T o2);
}
  • java.lang.Runnable
public interface Runnable {void run();
}
  • java.util.concurrent.Callable
public interface Callable<V> {V call() throws Exception;
}

实现起来基本上是这样的:

(o1, o2) -> o1.getXxx() > o2.getXxx()
() -> void
() -> V类型的对象

其中,callable最常见在多线程上,这里展示下我对于分布式锁的封装:

callable案例:分布式锁封装

2. 常用的函数式接口

或许对于Function、Predicate等等你并不陌生,好熟悉、好像在哪里用过就是想不起来!我们还是用stream()流来讲解。前提是构建一个用户列表:

构建数据

相信截图里User类的属性一目了然。现在我们用stream流来操作。

2.1 Function出现
List<String> nameList = users.stream().map(user -> user.getName()).collect(Collectors.toList());
log.info("nameList:{}", nameList);

这里的逻辑很简单,获得所有的用户名字返回集合。不知道有没有好奇过map,他的参数是什么:

map的参数

额,就是一个Function!好的,我这样改造下:

    static Function<User, String> nameFunction = user -> user.getName();public static void main(String[] args) {List<String> nameList = users.stream().map(nameFunction).collect(Collectors.toList());log.info("nameList:{}", nameList);}

其实Function就是两个类型约束,一个数参数类型,一个是返回值类型,定义了一个固定的逻辑。这个还好,如果稍加对于name的处理,并且是通用的处理方式,就可以考虑用Function写成一个通用的方法。

2.2 Predicate出现

Function类似,Predicate顾名思义,就是断言。可以从stream.filter()中获得:

User user1 = users.stream().filter(user -> "李四".equals(user.getName())).findFirst().orElse(null);
log.info("user1:{}", user1);

filter-predicate

对应的改造:

    static Predicate<User> namePredicate = user -> "李四".equals(user.getName());public static void main(String[] args) {User user1 = users.stream().filter(namePredicate).findFirst().orElse(null);log.info("user1:{}", user1);}

Predicate的范型只有一个,就是一个对象,返回的就是断言的方法。

2.3 Cousumer的出现

直接给出代码案例:

        Consumer<User> userConsumer = user -> {String name = user.getName();log.info("name:{}", name);};userConsumer.accept(users.get(0));

适用场景:访问类型T的对象,对其执行某些操作。只有操作,没有返回值,也不需要关注返回值。另外附上我最近看到的一段模板代码:

    /*** 利用设计模式减少样板代码*/public static void readLine(String filename, Consumer<String> consumer) {try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {String line;while ((line = reader.readLine()) != null) {consumer.accept(line);}} catch (IOException e) {throw new RuntimeException("Error reading file", e);}}public static void main(String[] args) {String filePath = "/Users/shigen/Downloads/area.json";readLine(filePath, (lines) -> {System.out.println(lines);});}  
2.4 Supplier的出现

还是先上代码:

        Supplier<User> userSupplier = () -> new User("10005", "shigen", null);User user2 = userSupplier.get();log.info("user2:{}", user2);userConsumer.accept(user2);

这里正好和Consumer相反,这里是生产对象的,然后可以供它消费。

适用场景:定义类型T的对象的生产规则。这里列出一个案例:生成随机数的方法:

        Supplier<Integer> randomSupplier = () -> new Random().nextInt(100);log.info("randomSupplier:{}", randomSupplier.get());

突然感觉曾经写过的工具类可以用这种方式简化一下了。

2.5 Comparator的出现

其实我们用的最多的还是实现Comparator的接口,重写compare方法用来比较对象,多见于需要内存排序的场景:

Comparator接口

也可以在stream.sorted()的参数中看出来:

stream.sorted()

        Comparator<User> userComparator =(user4, user5) -> user5.getName().compareTo(user4.getName());List<String> sortedName = users.stream().sorted(userComparator).map(User::getId).collect(Collectors.toList());log.info("sortedName:{}", sortedName);

当然,其它的高级复合Lambda表达式用法,可以参考这篇文章:系统学习lambda表达式。个人认为在业务代码使用复合lambda表达式,会加重代码的理解难度,不推荐。了解常见的函数式接口,并会使用即可。

与shigen一起,每天不一样!

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

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

相关文章

【我要成为配环境高手】Visual Studio中Qt安装与配置(无伤速通)

1.下载安装Qt和VSIX插件 2.本地环境变量配置 添加如下&#xff1a; D:\ProgramData\Qt\Qt5.14.2\5.14.2\msvc2017_64\libD:\ProgramData\Qt\Qt5.14.2\5.14.2\msvc2017_64\bin3.VS配置 ⭐项目右键->属性->调试->环境&#xff0c;添加如下&#xff1a;(很重要&#x…

随笔十、音频扩展模块测试

本项测试简单&#xff0c;对购买的音频扩展模块进行录音放音测试 按照使用说明&#xff0c;连接音频小板&#xff0c;一个喇叭一个麦克风&#xff0c;4根线&#xff0c;buildroot系统镜像 录音测试 rootRK356X:/# arecord -c 1 -r 44100 -f S16_LE /tmp/record.wav Recording …

【面试五】PID控制算法

一、 PID算法简介 PID&#xff08;Proportional-Integral-Derivative&#xff09;控制算法是一种经典的反馈控制方法&#xff0c;广泛应用于自动控制系统&#xff0c;例如温度控制、速度控制、位置控制等。 PID控制算法的核心包含三个部分&#xff1a;比例项&#xff08;P&…

Linux基础(包括centos7安装、linux基础命令、vi编辑器)

一、安装CentOS7 需要&#xff1a;1、VMware Workstation&#xff1b;2、CentOS7镜像 1、安装镜像 2、虚拟机配置 开启虚拟机&#xff0c;鼠标从vm中移出来用快捷键ctrlalt 点击开始安装&#xff0c;设置密码&#xff0c;等待安装完成,&#xff0c;重启。 3、注意事项 如果没…

CAN总线简介

CAN 是 Controller Area Network 的缩写&#xff08;以下称为 CAN&#xff09;&#xff0c;是 ISO国际标准化的串行通信协议。 历史背景 CAN 最初出现在80年代末的汽车工业中&#xff0c;由德国 Bosch 公司最先提出。当时&#xff0c;由于消费者对于汽车功能的要求越来越多&a…

android仿assistivetouch悬浮窗实现(带功能实现)

一、悬浮窗点击后的界面&#xff1a; 主要有四个功能&#xff0c;返回、应用程序、退出和主界面。其他功能也可以类似添加。 界面布局代码就不贴出来了&#xff0c;源码&#xff08;切记需要签名才能让功能实现&#xff09;&#xff1a;下载地址 二、主要是检测系统启动或者a…

动态规划法例题

第一个空&#xff0c;用手工计算&#xff0c;可以用贪心法 先选择价值最大的物品&#xff0c;有两个价值是6的物品&#xff0c;重量合计246 剩余4个空间&#xff0c;只能放重量为2的物品&#xff0c;一共是66315 第二个空&#xff0c;需要将所有物品都放进背包舱室&#xff…

基于Python的量化交易回测框架Backtrader初识记录(一)

版权声明&#xff1a;本文为博主原创文章&#xff0c;如需转载请贴上原博文链接&#xff1a;基于Python的量化交易回测框架Backtrader初识记录&#xff08;一&#xff09;-CSDN博客 前言&#xff1a;近期以来&#xff0c;对股市数据获取及预处理算是告一段落&#xff0c;下一步…

OpenCV绘图函数(5)绘制标记函数drawMarker()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::drawMarker 函数在 OpenCV 中用于在一个给定的位置上绘制标记。目前支持几种不同的标记类型&#xff0c;具体信息可以参考 MarkerTypes 函数…

【C++ | 设计模式】观察者模式的详解与实现

1.概念 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为型设计模式&#xff0c;它的核心思想是定义对象间的一对多依赖关系&#xff0c;当一个对象的状态发生变化时&#xff0c;所有依赖于它的对象都会收到通知并自动更新。这个模式在现实生活中非常常见&#…

Selenium的四种部署方式详解

关于selenium 的部署&#xff0c;我在网上找了很多&#xff0c;基本上都没有提到或是说的比较清晰的。当时我一直有个困惑&#xff1a;测试的脚本代码&#xff0c;是放在跟浏览器同一台机器上呢&#xff0c;还是放在Application Server上&#xff1f; 在官方开发文档中&#x…

从0开始深度学习(2)——自动微分

1 微积分 1.1 导数和微分 略 1.2 偏导数 略 1.3 梯度&#xff08;gradient&#xff09; 1.3.1 定义 对于一个多变量函数 f ( x 1 , x 2 , … , x n ) f\left(x_{1}, x_{2}, \ldots, x_{n}\right) f(x1​,x2​,…,xn​)其中点 a ( a 1 , a 2 , … , a n ) \mathbf{a}(a_…

YGG深海传奇,创造财富无限可能!

随著区块链技术的创新与游戏产业的深度融合&#xff0c;GameFi赛道迅速崛起&#xff0c;成为全球投资者与玩家瞩目的新兴领域。 成立于2020年的Yield Guild Games(YGG)&#xff0c;作为全球区块链游戏领域的先锋公会之一&#xff0c;也加入到向去中心化经济模式的转型浪潮当中。…

E. Sheep Eat Wolves

https://codeforces.com/gym/104869/problem/E 赛时队友想贪心&#xff0c;贪不了一点&#xff0c;我想了数学办法每次都送固定的发现送过去就不满足了 赛后补&#xff0c;暴力做O&#xff08;n4) 至少要几次才能把安全所有羊送到对岸去 考虑最短路,bfs,用数组存下所有状态 …

17:4层板层叠设置

层叠设置参考PCB专栏 设置平面内缩 GND内缩设置20mil0.508mm 电源层内缩设置要比GND内缩大&#xff0c;设置40mil1mm

米家商城主题 html 页面源码分享,可用于网页设计作业

使用技术&#xff1a; HTML, CSS , Javascript 项目亮点&#xff1a; 1. 仿照米家商城页面布局所做的页面样式结构 2. 首页放置了可自动切换的轮播图 3. 登录页有表单结构&#xff0c;并且有切换的动画效果 4. 包含实时的动态时间&#xff0c;使用 js 实现 5. 页面布局清…

Datawhale X 李宏毅苹果书AI夏令营深度学习详解入门Task02

本文了解深度学习详解中的线性模型 本文了解深度学习详解中的线性模型将围绕梯度下降优化、线性模型的局限性、改进模型以及深度学习模型等关键要点展开讨论。 一、梯度下降优化 梯度下降是深度学习中常用的优化算法&#xff0c;它通过不断调整模型的参数&#xff0c;使得损失函…

axios发送post请求实例

在body中的数据格式又有两种&#xff0c;一种是 json 数据格式&#xff0c;另一种是 字符串。具体要用哪种格式取决于后端入参的格式。 如果后端接收json数据类型&#xff0c;post 的 headers 需要设置 { ‘content-type’: ’application/json’ }&#xff0c;传给后端的数…

【王树森】BERT:预训练Transformer模型(个人向笔记)

前言 BERT&#xff1a;Bidirectional Encoder Representations from TransformerBERT是用来预训练Transformer模型的encoder的本节课只讲述主要思想BERT用两个主要思想来训练Transformer的encoder网络&#xff1a;①随机遮挡单词&#xff0c;让encoder根据上下文来预测被遮挡的…

Fine-Grained Egocentric Hand-Object(中文翻译)

精细化自我中心手-物体分割&#xff1a; 数据集、模型&#xff08;model&#xff09;与应用 灵芝张1, 盛昊周1, 西蒙斯滕特 $ {}^{2} $, 和健博石 $ {}^{1} $ 摘要。 自我中心视频提供了高保真度建模人类行为的细粒度信息。手和交互对象是理解观众行为和意图的一个关键方面。…