廖雪峰Java教程笔记杂
Java基础63
01面向对象基础(12)
02Java核心类(10)
03异常处理(4)
031Java的异常
所谓错误,就是程序调用某个函数的时候,如果失败了,就表示出错。
调用方如何获知调用失败的信息?有两种方法:
方法一:约定返回错误码。c常用,0正确,其他整数为约定错误码。
方法二:在语言层面上提供一个异常处理机制。
Java内置了一套异常处理机制,总是使用异常来表示错误。
异常是一种class,因此它本身带有类型信息。异常可以在任何地方抛出,但只需要在上层捕获,这样就和方法调用分离了.
可见,只要是方法声明的Checked Exception,不在调用层捕获,也必须在更高的调用层捕获。所有未捕获的异常,最终也必须在main()方法中捕获,不会出现漏写try的情况。这是由编译器保证的。main()方法也是最后捕获Exception的机会.如果不想写任何try代码,可以直接把main()方法定义为throws Exception.代价就是一旦发生异常,程序会立刻退出.
这种捕获后不处理的方式是非常不好的,即使真的什么也做不了,也要先把异常记录下来.所有异常都可以调用printStackTrace()方法打印异常栈,这是一个简单有用的快速打印异常的方法。
032捕获异常
多个catch语句只有一个能被执行
catch的顺序非常重要:子类必须写在前面
033抛出异常
printStackTrace()要从下向上看。
在代码中获取原始异常可以使用Throwable.getCause()方法。如果返回null,说明已经是“根异常”了。
绝大多数情况下,在finally中不要抛出异常。因此,我们通常不需要关心Suppressed Exception。
034自定义异常
保持一个合理的异常继承体系是非常重要的。
一个常见的做法是自定义一个BaseException作为“根异常”,然后,派生出各种业务类型的异常。
BaseException需要从一个适合的Exception派生,通常建议从RuntimeException派生。
自定义异常时,应该提供多种构造方法。
035NullPointerException
指针这个概念实际上源自C语言,Java语言中并无指针。我们定义的变量实际上是引用,Null Pointer更确切地说是Null Reference,不过两者区别不大。
036使用断言
断言不能用于可恢复的程序错误,只应该用于开发和测试阶段。
这是因为JVM默认关闭断言指令,即遇到assert语句就自动忽略了,不执行。
要执行assert语句,必须给Java虚拟机传递-enableassertions(可简写为-ea)参数启用断言
实际开发中,很少使用断言。更好的方法是编写单元测试,后续我们会讲解JUnit的使用。
04反射(5)
041Class类
由于JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息。
这种通过Class实例获取class信息的方法称为反射(Reflection)。
通过Class.newInstance()可以创建类实例,它的局限是:只能调用public的无参数构造方法。带参数的构造方法,或者非public的构造方法都无法通过Class.newInstance()被调用。
042访问字段
05注解
051使用注解
052定义注解
另一个重要的元注解@Retention定义了Annotation的生命周期:
仅编译期:RetentionPolicy.SOURCE;
仅class文件:RetentionPolicy.CLASS;
运行期:RetentionPolicy.RUNTIME。
如果@Retention不存在,则该Annotation默认为CLASS。因为通常我们自定义的Annotation都是RUNTIME,所以,务必要加上@Retention(RetentionPolicy.RUNTIME)这个元注解。
我们总结一下定义 Annotation的步骤:
1.用@intreface定义注解
2.添加参数,默认值,把最常用的参数定义为value,推荐所有参数都尽量设置默认值
3,.使用原注解配置注解。其中,必须设置@Target和@ Retention,@Retention一般设置为 RUNTIME。
053使用注解
因为注解定义后也是一种class,所有的注解都继承自java.lang.annotation.Annotation,因此,读取注解,需要使用反射API。
06泛型(7)
07集合(15)
071Java集合简介
Java标准库自带的java.util包提供了集合类:Collection,它是除Map外所有其他集合类的根接口。Java的java.util包主要提供了以下三种类型的集合:
List:一种有序列表的集合;
Set:一种保证没有重复元素的集合;
Map:一种通过键值(key-value)查找的映射表集合。
072List
所以我们要始终坚持使用迭代器Iterator来访问List,不同的List类型,返回的Iterator对象实现也是不同的,但总是具有最高的访问效率。
073编写equals方法
???????????????????????????????????????????练习中,使用Objects.equals就会报错,使用别的比如this.firstName.equals()是没有问题的。
074使用Map
和List类似,Map也是一个接口,最常用的实现类是HashMap。
Map不保证顺序,使用Map时,任何依赖顺序的逻辑都是不可靠的。
Map是一种映射表,可以通过key快速查找value。
可以通过for each遍历keySet(),也可以通过for each遍历entrySet(),直接获取key-value。
最常用的一种Map实现是HashMap
075编写equals和HashCode
HashMap之所以能根据key直接拿到value,原因是它内部通过空间换时间的方法,用一个大数组存储所有value,并根据key直接计算出value应该存储在哪个索引:
┌───┐
0 │ │
├───┤
1 │ ●─┼───> Person(“Xiao Ming”)
├───┤
2 │ │
├───┤
3 │ │
├───┤
4 │ │
├───┤
5 │ ●─┼───> Person(“Xiao Hong”)
├───┤
6 │ ●─┼───> Person(“Xiao Jun”)
├───┤
7 │ │
└───┘
076使用EnumMap
如果Map的key是enum类型,推荐使用EnumMap,既保证速度,也不浪费空间。
使用EnumMap的时候,根据面向抽象编程的原则,应持有Map接口。
????????????为什么写DayOfWeek.class
Map<DayOfWeek, String> map = new EnumMap<>(DayOfWeek.class);
077使用TreeMap
071Java集合简介
071Java集合简介
071Java集合简介
08IO(10)
IO是以内存为中心
Input指从外部读入数据到内存,例如,把文件从磁盘读取到内存,从网络读取数据到内存等等
Output指把数据从内存输出到外部,例如,把数据从内存写入到文件,把数据从内存输出到网络等等
IO流以byte(字节)为最小单位,因此也称为字节流。
如果我们需要读写的是字符,并且字符不全是单字节表示的ASCII字符,那么,按照char来读写显然更方便,这种流称为字符流。