Java8实战-总结2

news2024/12/27 15:19:08

Java8实战-总结2

  • 基础知识
    • 方法和Lambda
      • 传递代码:一个例子
      • 从传递方法到Lambda

基础知识

方法和Lambda

Scala和Groovy等语言的实践已经证明,让方法等概念作为一等值可以扩充程序员的工具库,从而让编程变得更容易。一旦程序员熟悉了这个强大的功能,就再也不愿意使用没有这一功能的语言了。因此,Java 8的设计者决定允许方法作为值,让编程更轻松。此外,让方法作为值也构成了其他若干Java 8功能(如Stream)的基础。

介绍的Java 8的第一个新功能是方法引用。比方说,想要筛选一个目录中的所有隐藏文件。需要编写一个方法,然后给它一个File,它就会告诉你文件是不是隐藏的。幸好,File类里面有一个叫作isHidden的方法。可以把它看作一个函数,接受一个File,返回一个布尔值。但要用它做筛选,需要把它包在一个FileFilter对象里,然后传递给File.listFiles方法,如下所示:

	File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
		public boolean accept(File file) {
			return file.isHidden();
		}
	});

虽然只有三行,但这三行可真够绕的。“非得这样不可吗?”已经有一个方法isHidden可以使用,为什么非得把它包在一个啰嗦的FileFilter类里面再实例化呢?因为在Java 8之前必须这么做!
如今在Java 8里,可以把代码重写成这个样子:

File[] hiddenFiles = new File(".").listFiles(File::isHidden);

已经有了函数isHidden,因此只需用Java 8的方法引用::语法(即“把这个方法作为值”)将其传给listFiles方法;请注意,开始用函数代表方法了。稍后会解释这个机制是如何工作的。一个好处是,代码现在读起来更接近问题的陈述了。方法不再是二等值了。与用对象引用传递对象类似(对象引用是用new创建的),在Java 8里写下File::isHidden的时候,就创建了一个方法引用,同样可以传递它。只要方法中有代码(方法中的可执行部分),那么用方法引用就可以传递代码。下图说明了这一概念:
在这里插入图片描述

Lambda——匿名函数
除了允许(命名)函数成为一等值外,Java 8还体现了更广义的将函数作为值的思想,包括Lambda"(或匿名函数)。比如,现在可以写(int x) -> x+1,表示“调用时给定参数x,就返回x+1值的函数”。可能会想这有什么必要呢?因为可以在MyMathsUtils类里面定义一个add1方法,然后写MyMathsUtils::add1嘛!确实是可以,但要是没有方便的方法和类可用,新的Lambda语法更简洁。使用这些概念的程序为函数式编程风格,这句话的意思是“编写把函数作为一等值来传递的程序。”。

传递代码:一个例子

来看一个例子,看看它是如何帮助写程序的。假设有一个Apple类,它有一个getColor方法,还有一个变量inventory保存着一个Apples的列表。想要选出所有的绿苹果,并返回一个列表。通常用筛选(filter)一词来表达这个概念。在Java 8之前,可能会写这样一个方法filterGreenApples:

	public static List<Apple> filterGreenApples(List<Apple> inventory) {
		List<Apple> result = new ArrayList<>();
		for (Apple apple: inventory){
			if("green".equals(apple.getcolor())) {
				result.add(apple);
			}
		}
		//高亮显示的代码会仅仅选出绿苹果
		return result;
	}

但是接下来,有人可能想要选出重的苹果,比如超过150克,于是写了下面这个方法:

public static List<Apple> filterHeavyApples(List<Apple> inventory){
	List<Apple> result = new ArrayList<>();
	for (Apple apple: inventory){
		if(apple.getWeight() > 150){
		这里高亮显示的代码会result.add(apple);仅仅选出重的苹果
		}
	}
	return result;
}

软件工程中复制粘贴的危险——给一个做了更新和修正,却忘了另一个。这两个方法只有一行不同:if里面的那行条件。如果这两个方法之间的差异仅仅是接受的重量范围不同,那么只要把接受的重量上下限作为参数传递给filter就行了,比如指定(150,1000)来选出重的苹果(超过150克),或者指定(0,80)来选出轻的苹果(低于80克)。

但是,前面提过了,Java8会把条件代码作为参数传递进去,这样可以避免filter方法出现重复的代码。现在可以写:

	public static boolean isGreenApple(Apple apple) {
		return "green".equals(apple.getcolor());
	public static boolean isHeavyApple(Apple apple) {
		return apple.getWeight() > 150;
	)
	public interface Predicate<T> { //写出来是为了清晰(平常只要从java.util.function导入就可以了)
		boolean test(T t);
	}
	
	static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p) {
		List<Apple> result = new ArrayList<>();
		for (Apple apple: inventory){
			if (p.test(apple)){
				result.add(apple);
			}
		}
		return result;
	}

要用它的话,可以写:


filterApples(inventory, Apple::isGreenApple);
或者
filterApples(inventory, Apple::isHeavyApple);
	什么是谓词?
	
	前面的代码传递了方法`Apple::isGreenApple`(它接受参数`Apple`并返回一个`boolean`)给`filterApples`,后者则希望接受一个`Predicate<Apple>`参数。
	谓词(predicate)在数学上常常用来代表一个类似函数的东西,它接受一个参数值,并返回true或false。在后面会看到,Java8也会允许
	写Function<Apple, Boolean>——在学校学过函数却没学过谓词的读者对此可能更熟悉,但用Predicate<Apple>是更标准的方式,效率也会更高一点儿,这避免了把boolean封装在Boolean里面。

从传递方法到Lambda

把方法作为值来传递显然很有用,但要是为类似于isHeavyAppleisGreenApple这种可能只用一两次的短方法写一堆定义有点儿烦人。不过Java 8也解决了这个问题,它引入了一套新记法(匿名函数或Lambda):

filterApples(inventory, (Apple a) -> "green".equals(a.getcolor()));

或者

filterApples(inventory, (Apple a) -> a.getWeight() > 150);

甚至

filterApples(inventory, (Apple a) -> a.getWeight() < 80 || "brown".equals(a.getcolor()));

甚至都不需要为只用一次的方法写定义;代码更干净、更清晰,因为用不着去找自己到底传递了什么代码。要是Lambda的长度多于几行(它的行为也不是一目了然)的话,那还是应该用方法引用来指向一个有描述性名称的方法,而不是使用匿名的Lambda。应该以代码的清晰度为准绳。

迄今为止谈到的函数式编程竟然如此强大。本来,Java加上filter和几个相关的东西作为通用库方法就足以让人满意了,比如

static <T> Collection<T> filter(Collection<T> c, Predicate<T> p);

这样甚至都不需要写filterApples了,因为比如先前的调用

filterApples(inventory, (Apple a)-> a.getWeight() > 150);

就可以直接调用库方法filter:

filter(inventory, (Apple a) -> a.getWeight() > 150);

但是,为了更好地利用并行,Java的设计师没有这么做。Java 8中有一整套新的类集合API——Stream,它有一套函数式程序员熟悉的、类似于filter的操作,比如mapreduce,还有在Collectionsstreams之间做转换的方法。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

理解LLM中的ReAct

large language models (LLMs)大语言模型在语义理解和交互式决策方面有着不错的表现。ReAct在一次交互中循环使用推理和行动两个操作解决复杂问题&#xff0c;推理即利用模型自身语义理解能力&#xff0c;行动则利用模型以外的能力&#xff08;如计算、搜索最新消息&#xff0c…

OpenCv之滤波器

目录 一、卷积 二、方盒滤波与均值滤波 三、高斯滤波 四、中值滤波 五、双边滤波 一、卷积 图像卷积就是卷积核在图像上按行华东遍历像素时不断的相乘求和的过程 相关知识点: 步长:就是卷积核在图像上移动的步幅.(为充分扫描图片&#xff0c;步长一般为1)padding:指在图片…

跨服务器跨库数据联合查询

今天群里有人问多个数据源, 可否显示在一个dbgrid, 我感觉是可以的 应该有两种办法 1,如果你两个服务器上都是用的mssqlserver, 那比较好办的, 如果不同数据库,如一个mssql,一个oracle。 则需要ssms方式创建。 通过SSMS查看,如果Microsoft OLE DB Provider for …

docekr-compose搭建redis集群(三主三从)

硬件&#xff1a;三台主机 172.50.2.40 172.50.2.41 172.50.2.42 需求&#xff1a;不想让它随机分配主从关系。想指定主从关系&#xff0c;如下&#xff1a; 主节点&#xff1a;172.50.2.40:6379&#xff0c;从节点172.50.2.41:6378 主节点&#xff1a;172.50.2.41:6379&…

C波段可调谐激光器控制软件系统

花了两周时间&#xff0c;利用下班时间&#xff0c;设计了一个ITLA可调谐激光器控制系统&#xff0c;从硬件到软件。下面这个图片整套硬件系统&#xff0c;软件硬件都自己设计&#xff0c;可以定制&#xff0c;做到单片机问题也不大。相当于一套光源了 这是软件使用的界面&…

PyTorch中的torch.nn.Linear函数解析

torch.nn是包含了构筑神经网络结构基本元素的包&#xff0c;在这个包中&#xff0c;可以找到任意的神经网络层。这些神经网络层都是nn.Module这个大类的子类。torch.nn.Linear就是神经网络中的线性层&#xff0c;可以实现形如yXweight^Tb的加和功能。 nn.Linear()&#xff1a;…

Linux网络---网络预备

文章目录 计算机网络背景计算机网络协议网络传输基本流程 网络中的地址管理 一、计算机网络背景 独立模式: 计算机之间相互独立; 网络互联: 多台计算机连接在一起, 完成数据共享; 局域网LAN: 计算机数量更多了, 通过交换机和路由器连接在一起 广域网WAN: 将远隔千里的计算机…

基于Javaweb实现ATM机系统开发实战(十二)用户转账功能实现

还是老规矩&#xff0c;先看前端传来怎样的参数&#xff1a; <% page language"java" contentType"text/html; charsetUTF-8" pageEncoding"UTF-8"%> <% taglib prefix"c" uri"http://java.sun.com/jsp/jstl/core"…

本地安装Linux虚拟机(超详细)

本文已收录于专栏 《运维》 目录 安装前准备虚拟机软件Linux镜像 安装过程中创建虚拟机安装linux系统 安装后测试 安装前准备 虚拟机软件 需要下载一个虚拟机软件&#xff0c;比如VirtualBox或VMware Workstation。这些软件可以创建和管理虚拟机。 这是VMware的官网&#xff1…

ceph集群(一)

ceph 一、存储基础分布式存储&#xff08;软件定义的存储 SDS&#xff09; 二、Ceph 简介Ceph 优势Ceph 架构Ceph 核心组件OSD 存储后端Ceph 数据的存储过程Ceph 集群部署 三、基于 ceph-deploy 部署 Ceph 集群实验Ceph 生产环境推荐&#xff1a;Ceph 环境规划部署 Ceph 集群 一…

Linux环境下,通过Docker搭建及配置RabbitMQ

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; Linux环境下&#xff0c;通过Docker搭建及配置RabbitMQ ⏱️ 创作时间…

SpringBoot--整合FreeMarker--使用/实例

原文网址&#xff1a;SpringBoot--整合FreeMarker--使用/实例_IT利刃出鞘的博客-CSDN博客 简介 本文介绍SpringBoot如何使用FreeMarker。 配置文件 application.yml spring:#模板引擎 freemarkerfreemarker:# 模板后缀suffix: .ftl# 是否启用模板缓存cache: false# 模板编…

二、MySQL启动和客户端连接

一、启动 方法一&#xff1a; 1、winR&#xff0c;输入services.msc&#xff0c;按回车 2、找到MySQL&#xff0c;右键-启动/停止 MySQL安装后&#xff0c;默认已启动。 方法二、 1、winR&#xff0c;输入cmd&#xff0c;打开命令行 2、输入启动与停止命令 二、客户端连接 …

如何使用ArcGIS Pro进行洪水淹没分析

伴随Esri将重心越来越多的放在ArcGIS Pro上,以后ArcGIS的使用场景可能会越来越少,所以我们可以提前接触并使用ArcGIS Pro,做好相关准备。这里为大家介绍一下在ArcGIS中常见的操作——洪水淹没分析在ArcGIS Pro中如何实现。 01 加载数据 在菜单栏上点击插入,点击新建地图,…

UEC++:HUD

绘制文字&#xff1a; Canvas&#xff1a;必须需要字体 Canvas的颜色设置&#xff1a; 不失真放大字体&#xff1a; 绘制图片&#xff1a; 复杂方式绘制图片&#xff1a; 绘制材质球&#xff1a; 绘制线条&#xff1a;起始位置&#xff0c;终点位置&#xff0c;颜色&#xff0c…

MySQL入门教程(1)

文章目录 一. 数据库简介1.1 什么是数据库1.2 数据库的分类 二. MySQL2.1 MySQL简介2.2 MySQL的客户端2.3 MySQL的服务器2.4 总结 一. 数据库简介 1.1 什么是数据库 数据库是一类软件, 帮助我们管理数据. 存储数据用文件就可以了&#xff0c;为什么还要弄个数据库? 文件保…

latex 好看的文本框框

嘿嘿&#xff0c;完全符合我的审美&#xff0c;我真是小机灵鬼~ 分享给大家 \begin{tcolorbox}[colbackgray!20, colframegray!100, sharp corners, leftrule{3pt}, rightrule{0pt}, toprule{0pt}, bottomrule{0pt}, left{2pt}, right{2pt}, top{3pt}, bottom{3pt}]blablabla …

React(3)

1.案例选项卡 import React, { Component } from reactexport default class App extends Component {state{tabList:[{id:1,text:"电影"},{id:2,text:"影院"},{id:3,text:"我的"}]}render() {return (<div><ul>{this.state.tabList…

verilog实现pwm呼吸灯

文章目录 verilog实现pwm呼吸灯一、简介二、代码设计三、仿真代码编写四、仿真结果五、总结 verilog实现pwm呼吸灯 一、简介 呼吸灯是指灯光在微电脑的控制之下完成由亮到暗的逐渐变化&#xff0c;感觉好像是人在呼吸。其广泛应用于手机之上&#xff0c;并成为各大品牌新款手…

杰理-AC695-页面之间跳转、页面内布局切换

杰理-AC695-页面之间跳转、页面内布局切换 //布局切换 ui_show(BT_MENU_LAYOUT); //页面切换 ui_hide_main(ID_WINDOW_BT); ui_show_main(ID_WINDOW_SYS);