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

news2024/11/22 15:26:19

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

  • 使用异常机制的技巧
  • 为什么要使用泛型程序设计
  • 定义简单泛型类
  • 泛型方法
    • 类型变量的限定
  • 泛型类型的继承规则

使用异常机制的技巧

1.异常处理不能代替简单的测试。 使用异常的基本规则是:只在异常情况下使用异常机制。

2.不要过分地细化异常。
很多程序员习惯将每一条语句都分装在一个独立的try语句块中。
最好将整个任务包装在一个try 语句块中,这样,当任何一个操作出现问题时,整个任务都可以取消。

try {
	for(i = 0; i < 100; i++) {
		n = s.pop();
		out.writeInt(n);
	}
}
catch (IOException e) {
	// problem writing to file
}
catch (EmptyStackException e) {
	// stack was empty 
}

3.利用异常层次结构。
不要只抛出RuntimeException异常。应该寻找更加适当的子类或创建自己的异常类。不要只捕获Thowable异常,否则,会使程序代码更难读、更难维护。

考虑受查异常与非受查异常的区别。已检查异常本来就很庞大,不要为逻辑错误抛出这些异常。

将一种异常转换成另一种更加适合的异常时不要犹豫。例如,在解析某个文件中的一个整数时,捕获NumberFormatException异常,然后将它转换成IOExceptionMySubsystemException的子类。

4.不要压制异常。
在Java中,往往强烈地倾向关闭异常。如果编写了一个调用另一个方法的方法,而这个方法有可能100年才抛出一个异常,那么,编译器会因为没有将这个异常列在throws表中产生抱怨。而没有将这个异常列在throws表中主要出于编译器将会对所有调用这个方法的方法进行异常处理的考虑。因此,应该将这个异常关闭:

public Image loadImage(String s) {
	try {
		// code that threatens to throw checked exceptions 
	}
	catch (Exception e) {} // so there 
}

现在,这段代码就可以通过编译了。除非发生异常,否则它将可以正常地运行。

5.在检测错误时,"苛刻"要比放任更好。
当检测到错误的时候,有些程序员担心抛出异常。在用无效的参数调用一个方法时,返回一个虚拟的数值,还是抛出一个异常,哪种处理方式更好?例如,当栈空时,Stack.pop是返回一个null,还是抛出一个异常?在出错的地方抛出一个EmptyStackException 异常要比在后面抛出一个NullPointerException异常更好。

6.不要羞于传递异常。
很多程序员都感觉应该捕获抛出的全部异常。如果调用了一个抛出异常的方法,例如,FilelnputStream构造器或readLine方法,这些方法就会本能地捕获这些可能产生的异常。其实,传递异常要比捕获这些异常更好:

public void readStuff(String filename)throws IOException { // not a sign of shame! 
	InputStream in = new FileInputStream(filename);
}

规则5、6可以归纳为“早抛出,晚捕获”。

为什么要使用泛型程序设计

泛型程序设计(Generic programming)意味着编写的代码可以被很多不同类型的对象所重用。例如,我们并不希望为聚集String和File对象分别设计不同的类。实际上,也不需要这样做,因为一个ArrayList类可以聚集任何类型的对象。这是一个泛型程序设计的实例。

定义简单泛型类

一个泛型类(generic class)就是具有一个或多个类型变量的类。以Pair类作为例子:

public class Pair<T> {
	private T first;
	private T second;
	
	public Pair() { first=null; second=null; }
	public Pair(T first,T second) { this.first = first; this.second = second; }
	
	public T getFirst(){ return first; }
	public T getSecond() { return second; }

	public void setFirst(T newValue){ first m newValue; }
	public void setSecond(T newValue){ second = newValue; }
}

Pair类引入了一个类型变量T,用尖括号<>括起来,并放在类名的后面。 泛型类可以有多个类型变量。例如,可以定义Pair类,其中第一个域和第二个域使用不同的类型:

public class Pair<T,U> {...}

类定义中的类型变量指定方法的返回类型以及域和局部变量的类型。 例如,

  private T first;// uses the type variable

类型变量使用大写形式。在 Java库中,使用变量E表示集合的元素类型,KV分别表示表的关键字与值的类型。T(需要时还可以用临近的字母US)表示“任意类型”。

用具体的类型替换类型变量就可以实例化泛型类型, 例如:

Pair<String>

可以将结果想象成带有构造器的普通类:

Pair<String>()
Pair<String>(String, String)

和方法:

String getFirst()
String getSecond()
void setFirst(String)
void setSecond(String)

换句话说,泛型类可看作普通类的工厂。

泛型方法

还可以定义带有类型参数的简单方法。

class ArrayAlg {
	public static <T> T getMiddle(T... a) {
		return a[a.length / 2];
	}
}

这个泛型方法是在普通类中定义的,而不是在泛型类中定义的。注意,类型变量放在修饰符(这里是public static)的后面,返回类型的前面。

泛型方法可以定义在普通类中,也可以定义在泛型类中。当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型

String middle = ArrayAlg.<String>getMiddle("John","Q.", "Public");

类型变量的限定

有时,类或方法需要对类型变量加以约束。下面是一个典型的例子。我们要计算数组中的最小元素:

class ArrayAlg {
	public static <T> T min(T[] a) { // almost correct 
		if (a == null || a.length == 0) {
			return null;
		}
		T smallest = a[0];
		for (int i = 1; i < a.length; i++) {
			if(smallest.compareTo(a[i])>0) { 
				smallest = a[i];
			}
		}
		return smallest;
	}
}

但是,这里有一个问题。min方法的代码内部,变量smallest类型为T,这意味着它可以是任何一个类的对象。怎么才能确信T所属的类有compareTo方法呢?
解决这个问题的方案是将T限制为实现了Comparable接口(只含一个方法compareTo的标准接口)的类。可以通过对类型变量T设置限定(bound) 实现这一点:

public static <T extends Comparable> T min(T[] a)... 

现在,泛型的min方法只能被实现了Comparable接口的类(如 String、LocalDate 等)的数组调用。
在此为什么使用关键字extends而不是implements?毕竟,Comparable是一个接口。

<T extends BoundingType>

表示T应该是绑定类型的子类型(subtype)。T和绑定类型可以是类,也可以是接口。 选择关键字 extends 的原因是更接近子类的概念。
一个类型变量或通配符可以有多个限定,例如:

T extends Comparable & Serializable

限定类型用“&”分隔,而逗号用来分隔类型变量。
在Java的继承中,可以根据需要拥有多个接口超类型,但限定中至多有一个类。如果用一个类作为限定,它必须是限定列表中的第一个。

泛型类型的继承规则

考虑一个类和一个子类,如Employee和Manager。Pair不是Pair的一个子类,下面的代码将不能编译成功:

Manager[] topHonchos = . . .;
Pair<Employee> result = ArrayAlg.minmax(topHonchos);// Error

minmax 方法返回Pair,而不是Pair,并且这样的赋值是不合法的。无论S与T有什么联系。
在这里插入图片描述

这一限制看起来过于严格,但对于类型安全非常必要。假设允许将Pair转换为Pair。考虑下面代码:

Pair<Manager> managerBuddies = new Pair<>(ceo, cfo);
Pair<Employee> employeeBuddies = managerBuddies; // illegal, but suppose it wasn't 
employeeBuddies.setFirst(lowlyEmployee);

显然,最后一句是合法的。但是employeeBuddiesmanagerBuddies引用了同样的对象。现在将cfo和一个普通员工组成一对,这对于Pair<Manager>来说应该是不可能的。

注意∶必须注意泛型与Java数组之间的重要区别。可以将一个Manager[]数组赋给一个类型为Employee[]的变量:

Manager[] managerBuddies = { ceo, cfo };
Employee[] employeeBuddies = managerBuddies; // OK

然而,数组带有特别的保护。如果试图将一个低级别的雇员存储到employeeBuddies[0],虚拟机将会抛出ArrayStoreException异常。

永远可以将参数化类型转换为一个原始类型。例如,Pair是原始类型Pair的一个子类型。在与遗留代码衔接时,这个转换非常必要。
但转换成原始类型之后会产生类型错误。比如下面这个示例:

Pair<Manager> managerBuddies = new Pair<>(ceo, cfo);
Pair rawBuddies = managerBuddies;// OK
rawBuddies.setFirst(new File("...."));// only a compile-time warning

当使用getFirst获得外来对象并赋给Manager变量时,与通常一样,会抛出 ClassCastException异常。这里失去的只是泛型程序设计提供的附加安全性。

泛型类可以扩展或实现其他的泛型类。 就这一点而言,与普通的类没有什么区别。例如,ArrayList<T>类实现List<T>接口。这意味着,一个ArrayList<Manager>可以被转换为一个List<Manager>。但是,,一个 ArrayList<Manager>不是一个ArrayList<Employee>List<Employee>
在这里插入图片描述

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

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

相关文章

第三章(3):深入理解Spacy库基本使用方法

第三章&#xff08;3&#xff09;&#xff1a;深入理解Spacy库基本使用方法 本章主要介绍了Spacy库的基本使用方法&#xff0c;包括安装、加载语言模型、分句、分词、词性标注、停用词识别、命名实体识别、依存分析和词性还原等内容。重点介绍了每个步骤的具体实现方式和应用场…

【TortoiseGit】安装和配置

转自 【TortoiseGit】TortoiseGit安装和配置详细说明_No8g攻城狮的博客-CSDN博客 一、TortoiseGit 简介 TortoiseGit 是基于 TortoiseSVN 的 Git 版本的 Windows Shell 界面。它是开源的&#xff0c;可以完全使用免费软件构建。 TortoiseGit 支持你执行常规任务&#xff0c;…

出道即封神的ChatGPT,现在怎么样了?ChatGPT想干掉测试人员,做梦去吧

从互联网的普及到智能手机&#xff0c;都让广袤的世界触手而及&#xff0c;如今身在浪潮中的我们&#xff0c;已深知其力。 前阵子爆火的ChatGPT&#xff0c;不少人保持观望态度。现如今&#xff0c;国内关于ChatGPT的各大社群讨论&#xff0c;似乎沉寂了不少&#xff0c;现在…

Mosquitto vs NanoMQ | 2023 MQTT Broker 对比

引言 Mosquitto 和 NanoMQ 都是用 C/C 开发的快速轻量的开源 MQTT Broker&#xff0c;完全支持 MQTT 3.1.1 和 5.0。 虽然 Mosquitto 和 NanoMQ 都具有轻量级和低资源消耗的特点&#xff0c;但它们的架构设计却截然不同。Mosquitto 采用单线程模式&#xff0c;而 NanoMQ 则基…

数据结构:单向链表(无头非循环)

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下数据结构方面有关链表的相关知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C语言专栏&#xff1a;C语言&#xff1a;从入门到…

【云原生】prometheus监控告警之安装部署alertmanager实战

前言 &#x1f3e0;个人主页&#xff1a;我是沐风晓月 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是沐风晓月&#xff0c;阿里云社区博客专家&#x1f609;&#x1f609; &#x1f495; 座右铭&#xff1a; 先努力成长自己&#xff0c;再帮助更多的人 &#xff0c…

Python基础知识:绝对/相对路径等

1 Python处理相对/绝对路径 由于本人在导入数据时&#xff0c;十分喜欢相对路径&#xff08;在数据的上一级文件中&#xff0c;新建文件夹保存处理整个代码处理过程&#xff09;&#xff0c;因此&#xff0c;将首先简单介绍下Python中相对/绝对路径的处理。 1.1 绝对路径 一…

状态压缩DP-蒙德里安的梦想

题意 求把 NM 的棋盘分割成若干个 12 的长方形&#xff0c;有多少种方案。 例如当 N2&#xff0c;M4 时&#xff0c;共有 5 种方案。当 N2&#xff0c;M3 时&#xff0c;共有 3 种方案。 如下图所示&#xff1a; 输入格式 输入包含多组测试用例。 每组测试用例占一行&#xff0…

Jupyter notebook安装教程

文章目录 前言一、安装步骤1、安装 Python 编译器2、安装 jupyter3、运行 Jupyter notebook 二、 更改打开文件位置和快捷启动方式1、更改打开文件位置2、创建快捷启动方式 前言 Jupyter Notebook 是以网页的形式打开&#xff0c;可以在网页页面中直接编写代码和运行代码&…

20230421 | 203. 移除链表元素、707. 设计链表、206. 反转链表

1、203. 移除链表元素 方法1&#xff1a;不添加虚拟节点方式&#xff0c;但是要注意处理删除头部的数据 时间复杂度 O(n) 空间复杂度 O(1) /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* List…

婚恋交友app开发中需要注意的安全问题

前言 随着移动设备的普及&#xff0c;婚恋交友app已经成为了人们生活中重要的一部分。但是&#xff0c;这些应用的开发者需要确保应用的安全性&#xff0c;以保护用户的隐私和数据免受攻击。本文将介绍在婚恋交友app开发中需要注意的安全问题。 在当今数字化时代&#xff0c;…

狗屁不通文章生成器下载-狗屁不通生成器网址

狗屁不通文章生成器 狗屁不通文章生成器&#xff08;也称为“吹牛生成器”&#xff09;是使用自然语言处理技术和机器学习算法生成随机文章的工具。这些文章往往没有意义&#xff0c;因为它们是从各种不相关的话语中随机组合而成的。 虽然这些文章看起来毫无意义&#xff0c;…

显卡GPU与CUDA

文章目录 1 什么是GPU1.1 独立显卡1.2 核心显卡 2 驱动3 深度学习显卡CUDA4 GPU VS CPU5 深度学习环境配置中各软件的关系windows下判断有无NVIDIA GPU16G512G8核14核 1 什么是GPU GPU就是显卡Graphics Processing Unit 图像处理单元显卡主要用于在屏幕上显示图像&#xff0c;…

ROS学习第二十六节——机器人仿真相关组件

1.URDF URDF是 Unified Robot Description Format 的首字母缩写&#xff0c;直译为统一(标准化)机器人描述格式&#xff0c;可以以一种 XML 的方式描述机器人的部分结构&#xff0c;比如底盘、摄像头、激光雷达、机械臂以及不同关节的自由度.....,该文件可以被 C 内置的解释器…

服务(第十篇)Nginx和tomcat反向代理(动静分离)

正向代理&#xff1a; 当用户想访问某一网址时&#xff0c;用户先访问代理服务器&#xff0c;然后由代理服务器向目标网址发送请求最终将数据返回代理服务器&#xff0c;最后代理服务器将数据返回给用户这一过程我们称之为正向代理。 反向代理&#xff1a;基本流程是与正向代理…

毕业-单片机-嵌入式~三年经历回顾

入行嵌入式软件开发 20年6月疫情第一次缓和、实操51单片机&#xff1b;20年9月郑州实习、温湿度采集类低功耗产品、初次接触ARM Cortex M0/M3 单片机&#xff1b;21年5月毕业来到杭州、不懂应届生的宝贵青春&#xff01;匆匆忙忙进厂&#xff5e;人生中第一个项目&#xff1a;…

使用vscode、cmake配置c++开发环境

使用vscode、cmake配置c开发环境 下载软件安装包VS codegcc编译器cmake 设置环境变量VS code插件安装 下载软件安装包 VS code 根据自己电脑选择合适版本下载安装即可。 官网链接&#xff1a;https://code.visualstudio.com/download gcc编译器 我使用的是mingw-w64编译器…

kong(2):docker搭建kong环境

Kong 安装有两种方式一种是没有数据库依赖的DB-less 模式&#xff0c;另一种是with a Database 模式。我们这里使用第二种带Database的模式&#xff0c;因为这种模式功能更全。 1 docker安装Kong 1.1构建Kong的容器网络 首先我们创建一个Docker自定义网络&#xff0c;以允许容…

022:Mapbox GL 加载geojson数据,形成热力图,自定义样式

第022个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中加载geojson数据,形成热力图. paint设置的参数:heatmap-color,heatmap-intensity,heatmap-opacity,heatmap-radius,heatmap-weight,visibility,具体请参考下面的api链接。 直接复制下面的 vue+mapbox源代…

如何实现网络安全的无缝衔接

随着信息技术的飞速发展&#xff0c;数字化转型已成为企业发展的必经之路。然而&#xff0c;随着技术进步带来的便利&#xff0c;网络安全问题也日益凸显。那么&#xff0c;在数字化转型的过程中&#xff0c;企业如何实现网络安全的无缝衔接呢&#xff1f; 一、网络安全与数字化…