Java核心技术 卷1-总结-7

news2024/11/23 15:06:58

Java核心技术 卷1-总结-7

  • lambda 表达式
    • 方法引用
    • 构造器引用
    • 变量作用域
    • 异常分类
    • 声明受查异常

lambda 表达式

方法引用

有时, 可能已经有现成的方法可以完成你想要传递到其他代码的某个动作。例如, 假设你希望只要出现一个定时器事件就打印这个事件对象。当然,为此也可以调用:

Timer t = new Timer(1000, event -> System.out.println(event));

但是,如果直接把 println 方法传递到Timer构造器就更好了。具体做法如下:

Timer t = new Timer(1000, System.out::println);

表达式 System.out::println是一个方法引用(method reference),它等价于lambda 表达式x->System.out.println(x)
假设你想对字符串排序,而不考虑字母的大小写。可以传递以下方法表达式:

Arrays.sort(strings, String::compareToIgnoreCase)

从这些例子可以看出,要用::操作符分隔方法名与对象或类名。主要有3种情况:

  • object::instanceMethod
  • Class::staticMethod
  • Class::instanceMethod

在前2种情况中,方法引用等价于提供方法参数的lambda表达式。前面已经提到,System.out::printin等价于x->System.out.println(x)。类似地,Math::pow 等价于(x,y) -> Math.pow(x,y)
对于第3种情况、第1个参数会成为方法的目标。例如,
String::compareTolgnoreCase等同于(x,y) -> x.compareTolgnoreCase(y)

如果有多个同名的重载方法,编译器就会尝试从上下文中找出你指的那一个方法。 例如,Math.max 方法有两个版本,一个用于整数,另一个用于double值。选择哪一个版本取决于Math::max转换为哪个函数式接口的方法参数。类似于lambda表达式,方法引用不能独立存在,总是会转换为函数式接口的实例。

可以在方法引用中使用this参数。 例如,this::equals等同于x->this.equals(x)。使用super也是合法的。下面的方法表达式super::instanceMethod使用this作为目标,会调用给定方法的超类版本。

构造器引用

构造器引用与方法引用很类似,只不过方法名为new。 例如,Person::new是Person构造器的一个引用。构造器取决于上下文。

变量作用域

通常,你可能希望能够在lambda表达式中访问外围方法或类中的变量。考虑下面这个例子:

public static void repeatMessage(String text, int delay) { 
	ActionListener listener = event -> {
		System.out.println(text);
		Toolkit.getDefaultToolkit().beep();
		};
	new Timer(delay, listener).start();
}

调用:repeatMessage("Hello",1000);// Prints Hello every 1,000 milliseconds。lambda表达式中的变量text并不是在这个lambda表达式中定义的。repeatMessage方法的一个参数变量。lambda表达式的代码可能会在repeatMessage调用返回很久以后才运行,而那时这个参数变量已经不存在了。如何保留text 变量呢?

要了解到底会发生什么,下面来巩固我们对lambda表达式的理解。lambda表达式有3 个部分:

  • 一个代码块;
  • 参数;
  • 自由变量的值,这是指非参数而且不在代码中定义的变量。

在上述例子中,这个lambda表达式有1个自由变量text。表示lambda表达式的数据结构必须存储自由变量的值,在这里就是字符串"Hello"。它被lambda表达式捕获(captured)。(具体的实现细节:例如,可以把一个lambda表达式转换为包含一个方法的对象,这样自由变量的值就会复制到这个对象的实例变量中。)

lambda表达式可以捕获外围作用域中变量的值。 要确保所捕获的值是明确定义的,这里有一个重要的限制。在lambda表达式中,只能引用值不会改变的变量。 例如,下面的做法是不合法的:

public static void countDown(int start, int delay) {
	ActionListener listener = event -> {
		start--; // Error: Can't mutate captured variable 
		System.out.println(start);
		};
	new Timer(delay, listener).start();
}

之所以有这个限制是有原因的。如果在lambda表达式中改变变量,并发执行多个动作时就会不安全。

另外如果在lambda表达式中引用变量,而这个变量可能在外部改变,这也是不合法的。 例如,下面就是不合法的:

public static void repeat(String text,int count) {
	for (int i= 1; i<= count; i++) {
		ActionListener listener = event -> {
			System.out.println(i + ":" + text);
			// Error: Cannot refer to changing i 
		};
		new Timer(1000, listener).start();
	}
}

这里有一条规则:lambda表达式中捕获的变量必须实际上是最终变量(effectively final)。 实际上的最终变量是指,这个变量初始化之后就不会再为它赋新值。在这里,text总是指示同一个String对象,所以捕获这个变量是合法的。不过,i的值会改变,因此不能捕获i。lambda表达式的体与嵌套块有相同的作用域。这里同样适用命名冲突和遮蔽的有关规则。在lambda表达式中声明与一个局部变量同名的参数或局部变量是不合法的。

Path first = Paths.get("/usr/bin");
Comparator<String> comp =
(first, second)-> first.length() - second.length();
// Error: Variable first already defined

在方法中,不能有两个同名的局部变量,因此,lambda表达式中同样也不能有同名的局部变量。

在一个lambda表达式中使用this关键字时,是指创建这个lambda表达式的方法的this参数。 例如,考虑下面的代码:

public class Application() {
	public void init() {
		ActionListener listener = event ->
		{
			System.out.println(this.toString ()); 
		}
	}
}

表达式this.toString()会调用Application对象的toString方法,而不是ActionListener实例的方法。在lambda表达式中,this的使用并没有任何特殊之处。lambda表达式的作用域嵌套在init方法中,与出现在这个方法中的其他位置一样,lambda表达式中this的含义并没有变化。

异常分类

在 Java 程序设计语言中, 异常对象都是派生于 Throwable 类的一个实例。如果 Java 中内置的异常类不能够满足需求,用户可以创建自己的异常类。
在这里插入图片描述
所有的异常都是由Throwable 继承而来,但在下一层立即分解为两个分支:Error和Exception。

Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。

在设计Java程序时,需要关注Exception层次结构。这个层次结构又分解为两个分支:一个分支派生于RuntimeException;另一个分支包含其他异常。 划分两个分支的规则是:由程序错误导致的异常属于RuntimeException;而程序本身没有问题,但由于像I/O错误这类问题导致的异常属于其他异常。
派生于RuntimeException的异常包含下面几种情况:

  • 错误的类型转换。
  • 数组访问越界。
  • 访问null指针。

不是派生于RuntimeException的异常包括:

  • 试图在文件尾部后面读取数据。
  • 试图打开一个不存在的文件。
  • 试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在。

应该通过检测数组下标是否越界来避免ArrayIndexOutOfBoundsException异常;应该通过在使用变量之前检测是否为null来杜绝NullPointerException异常的发生。

Java语言规范将派生于Error类或RuntimeException类的所有异常称为非受查(unchecked)异常,所有其他的异常称为受查(checked)异常。 编译器将核查是否为所有的受查异常提供了异常处理器。

声明受查异常

如果遇到了无法处理的情况,那么Java的方法可以抛出一个异常。一个方法不仅需要告诉编译器将要返回什么值,还要告诉编译器有可能发生什么错误。

方法应该在其首部声明所有可能抛出的异常。这样可以从首部反映出这个方法可能抛出哪类受查异常。

在自己编写方法时,不必将所有可能抛出的异常都进行声明。在遇到下面4种情况时应该抛出异常:

  • 调用一个抛出受查异常的方法,例如,FileInputStream 构造器。
  • 程序运行过程中发现错误,并且利用throw 语句抛出一个受查异常。
  • 程序出现错误,例如,a[-1] = 0会抛出一个ArrayIndexOutOfBoundsException这样的非受查异常。
  • Java虚拟机和运行时库出现的内部错误。

如果出现前两种情况之一,则必须告诉调用这个方法的程序员有可能抛出异常。因为如果没有处理器捕获这个异常,当前执行的线程就会结束。

对于那些可能被他人使用的Java方法,应该根据异常规范(exception specification),在方法的首部声明这个方法可能抛出的异常。

class MyAnimation {
	public Image loadImage(String s) throws IOException {
	}
}

不应该声明从RuntimeException继承的那些非受查异常。

class MyAnimation {
	void drawImage(int i) throws ArrayIndexOutOfBoundsException // bad style {
	}
}

这些运行时错误完全在我们的控制之下。如果特别关注数组下标引发的错误,就应该将更多的时间花费在修正程序中的错误上,而不是说明这些错误发生的可能性上。

一个方法必须声明所有可能抛出的受查异常,而非受查异常要么不可控制(Error),要么就应该避免发生(RuntimeException)。 如果方法没有声明所有可能发生的受查异常,编译器就会发出一个错误消息。

除了声明异常之外,还可以捕获异常。这样会使异常不被抛到方法之外,也不需要throws规范。

如果在子类中覆盖了超类的一个方法,子类方法中声明的受查异常不能比超类方法中声明的异常更通用(也就是说,子类方法中可以抛出更特定的异常,或者根本不抛出任何异常)。特别需要说明的是,如果超类方法没有抛出任何受查异常,子类也不能抛出任何受查异常。

如果类中的一个方法声明将会抛出一个异常,而这个异常是某个特定类的实例时,则这个方法就有可能抛出一个这个类的异常,或者这个类的任意一个子类的异常。例如,FilelnputStream构造器声明将有可能抛出一个IOExcetion异常,然而并不知道具体是哪种IOException异常。它既可能是IOException异常,也可能是其子类的异常,例如,FileNotFoundException

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

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

相关文章

使用@Scope注解设置组件的作用域

前言 Spring容器中的组件默认是单例的&#xff0c;在Spring启动时就会实例化并初始化这些对象&#xff0c;并将其放到Spring容器中&#xff0c;之后&#xff0c;每次获取对象时&#xff0c;直接从Spring容器中获取&#xff0c;而不再创建对象。 1.Scope注解概述 Scope注解能…

【uni-app】【01】底部导航栏与页面切换

1.(配置文件在哪)uni-app 路由控制是在 pages.json文件中的。 2.(基本配置项有哪些)初学的时候主要有三个配置项&#xff0c;①pages ② globalStyle ③ tabbar [!TOC] 接下来主要是对这三个配置项做一个简单介绍。 pages 负责页面管理。不需要自己写的&#xff0c;你在项目的p…

【Scala入门】scala基础语法:类和对象,变量和常量

上一篇请移步【Scala入门】Scala下载及安装&#xff08;Windows&#xff09;以及Idea创建第一个scala项目_水w的博客-CSDN博客 目录 一、Scala 二、Scala基础语法 2.1 注释与标识符规范 2.2 变量与常量 【案例&#xff1a;变量声明和赋值】 2.3 object 【案例&#xff1…

合并二叉树-递归法

1题目 给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些节点将会重叠&#xff08;而另一些不会&#xff09;。你需要将这两棵树合并成一棵新二叉树。合并的规则是&#xff1a;如果两个节点重叠…

gdb调试常用指令及案例讲解

文章目录 前言一、常用指令二、案例说明1、测试源文件2、编译和调试 三、其他指令四、案例说明 前言 GDB是一个由GNU开源组织发布的、UNIX/LINUX 操作系统下的、基于命令行的、功能强大的程序调试工具。 GDB 支持断点、单步执行、打印变量、观察变量、查看寄存器、查看堆栈等调…

【JavaEE】_2.文件与IO

目录 1.文件概述 1.1 文件的概念 1.2 文件的存储 1.3 文件的分类 1.4 目录结构 1.5 文件操作 1.5.1 文件系统操作 1.5.2 文件内容操作 2. Java文件系统操作 2.1 File类所处的包 2.2 构造方法 2.3 方法 2.3.1 与文件路径、文件名有关的方法 2.3.2 文件是否存在与普…

Java核心技术 卷1-总结-13

Java核心技术 卷1-总结-13 具体的集合散列集树集队列与双端队列优先级队列 映射基本映射操作 具体的集合 散列集 链表和数组可以有序的存储元素。但是&#xff0c;如果想要查看某个指定的元素&#xff0c;却又忘记了它的位置&#xff0c;就需要访问所有元素&#xff0c;直到找…

vue2数据响应式原理(5) 通过重写函数实现数组响应式监听

其实 我们之前对数组的一个监听 还并不是很完美 我们打开案例 打开 output.js 更改代码如下 import { observe } from "./dataResp" const output () > {var obj {data: {data: {map: {dom: {isgin: true}},arg: 13},name: "小猫猫"},bool: [1,2,3,4…

【经验与Bug】tensorflow草记

文章目录 1 常用小知识2 Learn1) 疑惑未解2) 为何要有"bias"&#xff1f; 3 问题处理1) jupyter的环境指定目录运行jupyter 2) Keras版本3) 为什么accuracy为100%&#xff0c;迭代时参数还在更新&#xff1f; 1 常用小知识 conda activate tf 在anaconda prompt使用&…

Android studio 播放音频文件 播放语速

一、使用 public class MainActivity extends AppCompatActivity {private Hsvolume mHsVolume null;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mHsVolume new Hsvolume(th…

【YOLO系列】YOLOv1论文笔记

论文链接&#xff1a;[1506.02640] You Only Look Once: Unified, Real-Time Object Detection (arxiv.org) YOLO将目标检测看作回归问题&#xff0c;使用单个神经网络直接从完整图像上预测边界框和类别概率。&#xff08;端到端&#xff1a;输入原始数据&#xff0c;输出的是最…

E5EAA HENF105240R1将用于工业生产过程的测量、控制和管理

​E5EAA HENF105240R1将用于工业生产过程的测量、控制和管理 工业控制计算机是工业自动化控制系统的核心设备 工业控制计算机是工业自动化设备和信息产业基础设备的核心。传统意义上&#xff0c;将用于工业生产过程的测量、控制和管理的计算机统称为工业控制计算机&#xff0c;…

SpringBoot整合WebSocket的两种方式及微服务网关Gateway配置

一、说明 项目中后台微服务需要向前端页面推送消息&#xff0c;因此不可避免的需要用到WebSocket技术。SpringBoot已经为WebSocket的集成提供了很多支持&#xff0c;只是WebSocket消息如何通过微服务网关Spring Cloud Gateway向外暴露接口&#xff0c;实际开发过程中遇到了很多…

【数据结构第四章】- 串的模式匹配算法(BF 算法和 KMP 算法/用 C 语言实现)

目录 一、前言 二、BF 算法 三、KMP 算法 3.2.1 - KMP 算法的原理 3.2.2 - KMP 算法的实现 3.2.3 - KMP 算法的优化 创作不易&#xff0c;可以点点赞&#xff0c;如果能关注一下博主就更好了~ 一、前言 子串的定位运算通常称为串的模式匹配或串匹配。此运算的应用非常广…

美国主机的带宽和网络速度究竟有多快?

在选择一个主机时&#xff0c;其带宽和网络速度是非常重要的考虑因素。而美国主机在带宽和网络速度方面有着明显的优势&#xff0c;成为了众多用户的首选。那么&#xff0c;美国主机的带宽和网络速度究竟有多快呢?本文将通过分析美国主机的网络基础设施和数据中心设施&#xf…

golang入门项目——打卡抽奖系统

功能介绍 用户加入群组之后&#xff0c;会在签到群组所设的签到地点进行签到和签退&#xff0c;并限制同一个设备只能签到一个用户&#xff0c;签到成功之后。会获取一定的限制在该群组使用的积分。该群组可以设置一些抽奖活动&#xff0c;用户可使用该群组内的积分来进行该群…

Python+mysql+php搭建另类免费代理池

文章目录 前言:思路&#xff1a;开干&#xff1a;php连接MySQL取ip和端口&#xff1a;效果图&#xff1a; 最后调用代理池&#xff1a;总结&#xff1a; 前言: 为什么说另类的&#xff0c;因为我完全是按照我自己的想法来的&#xff0c;比较鸡肋&#xff0c;但是能用&#xff…

短视频app开发:如何提高视频播放稳定性

简介 如今&#xff0c;短视频已经成为人们日常生活中不可或缺的一部分&#xff0c;而短视频app的开发也日益成为了人们热议的话题。在短视频app开发的过程中&#xff0c;如何提高视频播放稳定性是一个非常重要的问题。本文将从短视频源码角度出发&#xff0c;分享提高短视频ap…

如何优化语音交友app开发的搜索和匹配算法

语音交友app开发的挑战 在当今社交媒体行业中&#xff0c;语音交友app开发已经成为一个热门的领域。越来越多的人开始使用语音交友app来寻找新的朋友&#xff0c;这也为开发者们带来了许多机会。然而&#xff0c;这个领域也面临着一些挑战。其中一个最大的挑战是如何优化搜索和…

掏空腰包,日子难过,机缘转岗软件测试,这100个日夜的心酸只有自己知道...

我今年27岁&#xff0c;原本从事着土木工程相关的工作&#xff0c;19年开始有了转行的想法... 大学刚毕业那年&#xff0c;我由于学的是土木工程专业&#xff0c;自然而然的从事了和土木工程相关的工作&#xff0c;房贷、车贷&#xff0c;在经济的高压下&#xff0c;当代社会许…