Java8实战-总结6

news2024/11/6 3:12:03

Java8实战-总结6

  • 通过行为参数化传递代码
    • 对付啰嗦
      • 匿名类
        • 第五次尝试:使用匿名类
        • 第六次尝试:使用Lambda表达式
        • 第七次尝试:将List类型抽象化
    • 真实的例子
      • 用Comparator来排序

通过行为参数化传递代码

对付啰嗦

人们不愿意用那些很麻烦的功能或概念。目前,当要把新的行为传递给filterApples方法的时候,不得不声明好几个实现ApplePredicate接口的类,然后实例化好几个只会提到一次的ApplePredicate对象。下面的程序总结了目前的一切。这很啰嗦,很费时间:

	public class AppleHeavyWeightPredicate implements ApplePredicate {
		public boolean test(Apple apple) { //选择较重苹果的谓词
			return apple.getWeight()> 150;
		}
	}

	public class AppleGreenColorPredicate implements ApplePredicate{  
		public boolean test(Apple apple) { //选择绿苹果的谓词
			return "green".equals(apple.getcolor());
		}
	}

	public class FilteringApples {
		public static void main(String...args) {
			List<Apple> inventory = Arrays.asList(new Apple(80,"green"), new Apple(155,"green"), new Apple(120,"red"));
			//结果是一个包含一个155克Apple的List
			List<Apple> heavyApples = filterApples(inventory, new AppleHeavyWeightPredicate());
			//结果是一个包含两个绿Apple的List
			List<Apple> greenApples = filterApples(inventory, new AppleGreenColorPredicate());
		}
	
		public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) {
			List<Apple> result = new ArrayList<>();
			for (Apple apple : inventory) {
				if (p.test(apple)) {
					result.add(apple);
				}
			}
			return result;
		}
	}

能不能做得更好呢?Java有一个机制称为匿名类,它可以同时声明和实例化一个类。它可以帮助进一步改善代码,让它变得更简洁。但这也不完全令人满意。

匿名类

匿名类和Java局部类(块中定义的类)差不多,但匿名类没有名字。它允许同时声明并实例化一个类。换句话说,它允许随用随建。

第五次尝试:使用匿名类

下面的代码展示了如何通过创建一个用匿名类实现ApplePredicate的对象,重写筛选的例子:

//直接内联参数化filterapples方法的行为
	List<Apple> redApples = filterApples(inventory, new ApplePredicate() {
		public boolean test (Apple apple) {
			return "red".equals(apple.getcolor());
		}
	});

GUI应用程序中经常使用匿名类来创建事件处理器对象(下面的例子使用的是JavaFX API,一种现代的Java UI平台):

	button.setOnAction(new EventHandlercActionEvent>() {
		public void handle(ActionEvent event) {
			System.out.println("Woooo a click!!");
		}
	});

但匿名类还是不够好。第一,它往往很笨重,因为它占用了很多空间。还拿前面的例子来看,如下面高亮的代码所示:

//很多模板代码
List<Apple> redApples = filterApples(inventory, new ApplePredicate() {   
	public boolean test(Apple a) {
		return "red".equals(a.getcolor());
	}
});

button.setOnAction(new EventHandler<ActionEvent>() {
	public void handle(ActionEvent event) {
		System.out.println("Woooo a click!!");
	}
});

第二,很多程序员觉得它用起来很让人费解。比如,如下展示的一个经典的Java谜题,它让大多数程序员都措手不及:

下面的代码执行时会有什么样的输出呢,456还是42?

public class MeaningofThis
{
	public final int value = 4;
	public void doIt()
	{
		int value = 6;
		Runnable r = new Runnable() {
			public final int value = 5;
			public void run() {
				int value = 10;
				System.out.println(this.value);
			}
		};
		r.run();
	}
	
	public static void main(String...args)
	{
		MeaningOfThis m = new MeaningofThis();
		//这一行的输出是什么?
		m.doIt();
	}
}


答案是5,因为this指的是包含它的Runnable,而不是外面的类MeaningOfThis

整体来说,啰嗦就不好;它让人不愿意使用语言的某种功能,因为编写和维护啰嗦的代码需要很长时间,而且代码也不易读。好的代码应该是一目了然的。即使匿名类处理在某种程度上改善了为一个接口声明好几个实体类的啰嗦问题,但它仍不能令人满意。在只需要传递一段简单的代码时(例如表示选择标准的boolean表达式),你还是要创建一个对象,明确地实现一个方法来定义一个新的行为(例如Predicate中的test方法或是EventHandler中的handler方法)。
在理想的情况下,我们想鼓励程序员使用行为参数化模式,因为正如你在前面看到的,它让代码更能适应需求的变化。在第3章中,你会看到Java8的语言设计者通过引入Lambda表达式——一种更简洁的传递代码的方式——解决了这个问题。好了,悬念够多了,下面简单介绍一下Lambda表达式是怎么让代码更干净的。

第六次尝试:使用Lambda表达式

上面的代码在Java 8里可以用Lambda表达式重写为下面的样子:

List<Apple> result = filterApples(inventory, (Apple apple) -> "red".equals(apple.getcolor()));

不得不承认这代码看上去比先前干净很多。这很好,因为它看起来更像问题陈述本身了。现在已经解决了啰嗦的问题。下图对到目前为止的工作做了一个小结。
在这里插入图片描述

第七次尝试:将List类型抽象化

在通往抽象的路上,还可以更进一步。目前,filterApples方法还只适用于Apple。还可以将List类型抽象化,从而超越眼前要处理的问题:

	public interface Predicate<T> {
		boolean test (T t);
	}
	
	//引入类型参数T
	public static <T> List<T> filter(List<T> list, Predicate<T> p) {
		List<T> result = new ArrayList<>();
		for(T e: list) {
			if(p.test(e)) {
				result.add(e);
			}
		}
		return result;
	}

现在可以把filter方法用在香蕉、桔子、Integer或是String的列表上了。这里有一个使用Lambda表达式的例子:

List<Apple> redApples = filter(inventory,(Apple apple) -> "red".equals(apple.getcolor()));

List<Integer> evenNumbers = filter(numbers, (Integer i) -> i % 2 == 0);

现在在灵活性和简洁性之间找到了最佳平衡点,这在Java 8之前是不可能做到的。

真实的例子

现在已经看到,行为参数化是一个很有用的模式,它能够轻松地适应不断变化的需求。这种模式可以把一个行为(一段代码)封装起来,并通过传递和使用创建的行为(例如对Apple的不同谓词)将方法的行为参数化。前面提到过,这种做法类似于策略设计模式。Java API中的很多方法都可以用不同的行为来参数化。这些方法往往与匿名类一起使用。展示三个例子:用一个Comparator排序,用Runnable执行一个代码块,以及GUI事件处理。

用Comparator来排序

对集合进行排序是一个常见的编程任务。比如,那位农民朋友想要根据苹果的重量对库存进行排序,或者他可能改了主意,希望根据颜色对苹果进行排序。听起来有点儿耳熟?是的,需要一种方法来表示和使用不同的排序行为,来轻松地适应变化的需求。

Java8中,List自带了一个sort方法(也可以使用Collections.sort)。sort的行为可以用java.util.Comparator对象来参数化,它的接口如下:

	// java.util.Comparator
	public interface Comparator<T> {
		public int compare(T o1, T o2);
	}

因此,可以随时创建Comparator的实现,用sort方法表现出不同的行为。比如,可以使用匿名类,按照重量升序对库存排序:

	inventory.sort (new Comparator<Apple>() {
		public int compare(Apple al, Apple a2) {
			return al.getWeight().compareTo(a2.getWeight());
		}
	});

如果农民改了主意,可以随时创建一个Comparator来满足他的新要求,并把它传递给sort方法。而如何进行排序这一内部细节都被抽象掉了。用Lambda表达式的话,看起来就是这样:

	inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight())));

现在暂时不用担心这个新语法,之后会详细讲解如何编写和使用Lambda表达式。

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

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

相关文章

个微API,微信机器人开发

简要描述&#xff1a; 退出群聊 请求URL&#xff1a; http://域名地址/quitChatRoom 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说明wI…

Redis实战案例24-关注推送

1. Feed流实现方案 拉模式主要缺点&#xff0c;延迟问题&#xff0c;极端情况某个用户关注了成千上万的up主&#xff0c;每位up主又发布了十几条博客&#xff0c;此时拉模式的延迟就会很高&#xff1b; 推模式缺点也很明显&#xff0c;内存消耗太大&#xff0c;假设up主是千万级…

【idea工具】idea工具,build的时候提示:程序包 com.xxx.xx不存在的错误

idea工具&#xff0c;build的时候提示:程序包 com.xxx.xx不存在的错误&#xff0c;如下图&#xff0c;折腾了好一会&#xff0c; 做了如下操作还是不行&#xff0c;idea工具编译的时候&#xff0c;还是提示 程序包不存在。 a. idea中&#xff0c;重新导入项目&#xff0c;也还…

基于DNN深度学习网络的OFDM+QPSK信号检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ............................................................................. Transmitt…

区块链实验室(11) - PBFT耗时与流量特征

以前面仿真程序为例&#xff0c;分析PBFT的耗时与流量特征。实验如下&#xff0c;100个节点构成1个无标度网络&#xff0c;节点最小度为5&#xff0c;最大度为38. 从每个节点发起1次交易共识。统计每次交易的耗时以及流量。本文所述的流量见前述仿真程序的说明:区块链实验室(3)…

页面设计—FlexContainer弹性容器组件详解

一、组件介绍 Flex 是 Flexible Box 的缩写&#xff0c;意为"弹性布局"&#xff0c;用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为 Flex 布局&#xff0c;可以与栅格布局结合使用。 二、样式介绍 三、如何使用 &#xff08;1&#xff09;找到FlexCo…

实用!SD人物表情提示词合辑;秒变大神的Python速查表;开源LLM微调训练指南;LLM开发必修课 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 太实用了&#xff01;Stable Diffusion 的24个表情提示词 Pensive 沉思 Smiling 微笑 Disgusted 厌恶 Laughing 大笑 Shocked 震惊 Fr…

【数据分析专栏之Python篇】全网最细Anaconda安装与配置

文章目录 [toc] 前言一、 Anaconda是什么1.1 简介1.2 特点1.3 Anaconda、conda、pip、virtualenv的区别 二、为什么使用Anaconda三、安装步骤3.1 下载安装3.2 配置conda源 四、结语五、附录六、参考 前言 大家好&#xff01;本篇给大家介绍 Anaconda 安装及配置。 一、 Anaco…

【分享】揭秘BlueWillow::AI绘画工具的平替新选择

哈喽&#xff0c;木易巷上线啦&#xff01; 今天我要给大家介绍一个全新的AI绘画工具——BlueWillow。如果你正在寻找一款能够替代Midjourney的工具&#xff0c;那么BlueWillow绝对值得一试&#xff01; 官网链接和邀请链接都在最后哦&#xff01; 首先&#xff0c;BlueWillo…

< 今日小技巧:Axios封装,接口请求增加防抖功能 >

文章目录 &#x1f449; 前言&#x1f449; 一、核心代码 &#xff1a; 防抖函数&#x1f449; 二、Axios封装中的配置&#x1f449; 三、实现原理&#x1f449; 结论&#x1f449; 补充优化&#xff1a; 解决多个接口请求&#xff0c;拦截掉了需要的请求> 防抖函数> 引用…

c 学习笔记(自用)---GCC编译器

1.GCC编译器的使用 1&#xff09; 一个c文件预处理和编译的过程 可以用以上命令去逐步调试下&#xff0c;看看预处理的过程 2&#xff09;命令举例与解释 #源文件较少的情况下 gcc -o test main.c sub.c #分别将 main.c 和sub.c文件进行预处理、编译、汇编&#xff0c; #…

push_back 和 emplace_back 的区别

文章目录 1、vector::push_back1.1 void push_back(T&& x) ; (C11)参数返回值类型大小 和 容量移动左值用户自定义类型使用 push_back 1.2 void push_back(const T &x);参数返回值类型 1.3 如果 vector 的 size 超过当前capacity&#xff0c;push_back 会使迭代器、…

一分钟学一个 Linux 命令 - rm

前言 大家好&#xff0c;我是 god23bin&#xff0c;欢迎回到咱们的《一分钟学一个 Linux 命令》系列&#xff0c;今天我要讲的是一个比较危险的命令&#xff0c;rm 命令&#xff0c;没错&#xff0c;你可以没听过 rm 命令&#xff0c;但是删库跑路你不可能没听过吧&#xff1f…

RISCV -3 RV32I/RV64I基本整型指令集

RISCV -3 RV32I/RV64I基本整型指令集 1 RV32I Base Integer Instruction Set1.1 Programmers’ Model for Base Integer ISA1.2 Base Instruction Formats1.3 Immediate Encoding Variants1.4 Integer Computational Instructions1.4.1 Integer Register-Immediate Instruction…

25-30天每日强训选择题改错解析

int i5; int s(i)(i)(i–)(–i); s( )//s 的值是什么&#xff1f; A 28 B 25 C 21 D 26 E 24 F 23 正确答案&#xff1a; E 5775 24 或者 --在后先不变化数值 -- 在前先变化再运算 以下哪项不属于java类加载过程&#xff1f; A 生成java.lang.Class对象 B int类型对象成…

【Vue】day04-组件通信

day04 一、学习目标 1.组件的三大组成部分&#xff08;结构/样式/逻辑&#xff09; scoped解决样式冲突/data是一个函数 2.组件通信 组件通信语法 父传子 子传父 非父子通信&#xff08;扩展&#xff09; 3.综合案例&#xff1a;小黑记事本&#xff08;组件版&#xf…

Windows下达梦数据库图形化安装、初始化数据库及连接

文章目录 前言一、达梦数据库安装1、下载安装包2、解压3、安装 二、初始化数据库三、连接数据库1、客户端工具2、输入连接信息3、成功连接 总结 前言 本节将介绍达梦数据库的图形化界面安装的细节&#xff0c;本节以Win11系统及DM8为基础进行讲解&#xff0c;虽然是图形化安装…

5. Bean 的作用域和生命周期

目录 1. Bean 被修改的案例 2. 作用域定义 2.1 Bean 的 6 种作用域 singleton prototype request session application&#xff08;了解&#xff09; websocket &#xff08;了解&#xff09; 单例作用域&#xff08;singleton&#xff09;VS 全局作用域&#xff08;…

企业知识管理系统安全是重中之重

企业开展知识管理工作的益处是全方位的&#xff0c;效果能从业务的各方面得到体现&#xff0c;最终效果就是企业竞争力的提升与企业经营业绩的提升。 知识管理系统的意义在于&#xff0c;构建系统的知识库&#xff0c;对纷杂的知识内容&#xff08;方案、策划、制度等&#xf…

【业务功能篇51】对象复制的三种方式 工具类Orika、反射、BeanUtils浅拷贝

业务场景&#xff1a; 设计规范前提下&#xff0c;我们数据层传输承载的是用DTO&#xff0c;而到控制层返回给前端会对应定义一个VO对象&#xff0c;比如是一个问题单数据集合list<DTO>,数据层接收的是DTO对对象&#xff0c;到控制层接收后需要转换成list<VO>,这里…