一、 枚举和注解
1. 枚举的概述
枚举 (enumeration),是一组常量的集合
枚举属于一种特殊的类,里面只包含一组有限的特定对象
枚举的两种实现方式:自定义类实现枚举 和 enum关键字实现枚举
(1) 自定义类实现枚举
① 不需要提供 setXxx 方法,因为枚举对象值通常为只读
② 对枚举对象/属性使用 final + static 共同修饰,实现底层优化
③ 枚举对象名通常使用全部大写,常量的命名规范
④ 枚举对象根据需要,也可以有多个属性
特点: ① 构造器私有化
② 本类内部创建一组对象 [四个 春夏秋冬]
③ 对外暴露对象 (通过为对象添加 public final static 修饰符)
④ 可以提供 get 方法,但不要提供 set
(2) enum关键字实现枚举
① 当我们使用 enum 关键字开发一个枚举类时,默认会继承 Enum 类,
而且是一个 final 类
② 传统的 public static final Season SPRING = new Season("春天","温暖"),
简化成 SPRING("春天","温暖"),这里必须知道它调用的是哪个构造器
常量名(实参列表)
③ 如果使用无参构造器创建枚举对象,则实参列表和小括号都可以省略
④ 当有多个枚举对象时,使用逗号间隔,最后有一个分号结尾
⑤ 枚举对象必须放在枚举类的行首
package com.hhh.enum_;
public class Enumeration {
public static void main(String[] args) {
System.out.println(Season.AUTUMN);
System.out.println(Season.SUMMER);
}
}
enum Season2 {
//定义了四个对象, 固定.
// public static final Season SPRING = new Season("春天", "温暖");
// public static final Season WINTER = new Season("冬天", "寒冷");
// public static final Season AUTUMN = new Season("秋天", "凉爽");
// public static final Season SUMMER = new Season("夏天", "炎热");
//如果使用了 enum 来实现枚举类
//1. 使用关键字 enum 替代 class
//2. public static final Season SPRING = new Season("春天", "温暖")
// 直接使用SPRING("春天", "温暖")
//3. 如果有多个常量(对象), 使用 ,号间隔即可
//4. 如果使用 enum 来实现枚举,要求将定义常量对象,写在前面
//5. 如果我们使用的是无参构造器,创建常量对象,则可以省略 ()
SPRING("春天", "温暖"), WINTER("冬天", "寒冷"), AUTUMN("秋天", "凉爽"),
SUMMER("夏天", "炎热")/*, What()*/;
private String name;
private String desc;//描述
private Season2() {
//无参构造器
}
private Season(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season{" + "name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
2) enum 常用方法应用实例
① toString:Enum 类已经重写过了,返回的是当前对象名,子类可以
重写该方法,用于返回对象的属性信息
Season autumn = Season.AUTUMN;
System.out.println(autumn);
② name:返回当前对象名(常量名),子类中不能重写
System.out.println(autumn.name());
③ ordinal:返回当前对象的位置号,默认从0开始
System.out.println(autumn.ordinal());
④ values:返回当前枚举类中所有的常量
Season[] values = Season.values();
for(Season season:Season.values){
System.out.println(season);
}
⑤ valueOf:将字符串转换成枚举对象,要求字符串必须为已有的常量名,
否则报异常!
Season value = Season.valueOf("SPRING");
System.out.println(value);
⑥ compareTo:比较两个枚举常量,比较的就是位置号!
System.out.println(autumn.compareTo(value));
3) enum 实现接口
① 使用 enum 关键字后,就不能再继承其他类了,因为 enum 会隐式继承 Enum,
而 Java 是单继承机制
② 枚举类和普通类一样,可以实现接口
enum 类名 implement 接口1,接口2{}
2. 注解的理解
① 注解 (Annotation) 也被称为元数据 (Metadata),用于修饰解释 包、类、方法、
属性、构造器、局部变量等数据信息
② 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入
在代码中的补充信息
③ 在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。
在 JavaEE 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,
代替 Java EE 旧版中所遗留的繁冗代码和 XML 配置等
(2) 基本的 Annotation 介绍
使用 Annotation 时要在其前面增加 @ 符号,并把该 Annotation 当成一个
修饰符使用,用于修饰它支持的程序元素。
三个基本的 Annotation:
① @Override:限定某个方法,是重写父类方法,该注解只能用于方法
//@interface 不是 interface,是注解类
② @Deprecated:用于表示某个程序元素(类,方法等)已过时
③ @SuppressWarnings:抑制编译器警告
1) @Override 使用说明
① @Override 表示指定重写父类的方法 (从编译层面验证),如果父类
没有 fly 方法,则会报错
② 如果不写 @Override 注解,而父类仍有 public void fly(){},仍然构成重写
③ @Override 只能修饰方法,不能修饰其他类,包,属性等等
④ 查看 @Override 注解源码为 @Target(ElementType.METHOD),
说明只能修饰方法
⑤ @Target 是修饰注解的注解,称为元注解
2) @Deprecated 使用说明
① 用于表示某个程度元素(类,方法等)已过时
② 可以修饰方法,类,字段,包,参数等
③ @Target(value={CONSTRUCTOR,FIELD,LOCAL_VARIABLE,
METHOD,PACKAGE,PARAMETER,TYPE})
④ @Deprecated 的作用可以做到新旧版本的兼容和过渡
3) @SuppressWarnings 使用说明
① unchecked 是忽略没有检查的警告
例如:@SuppressWarnings(“unchecked”);
② rawtypes 是忽略没有指定泛型的警告(传参时没有指定泛型的警告错误)
③ unused 是忽略没有使用某个变量的警告错误
④ @SuppressWarnings 可以修饰的程序元素为,查看@Target
⑤ 生成 @SuppressWarnings 时,直接点击左侧的黄色提示,就可以选择
(注意可以指定生成的位置)
3. JDK内置的元 Annotation (元注解)
JDK 的元 Annotation 用于修饰其他 Annotation
(2) 元注解的种类
① Retention //指定注解的作用范围,三种 SOURCE,CLASS,RUNTIME
② Target //指定注解可以在哪些地方使用
③ Documented //指定该注解是否会在 javadoc 体现
④ Inherited //子类会继承父类注解
1) @Retention 注解
只能用于修饰一个 Annotation 定义,用于指定该 Annotation 可以保留多长时间,
@Retention 包含一个 RetentionPolicy 类型的成员变量,使用 @Retention 时必须为
该 value 成员变量指定值
@Retention 的三种值:
① RetentionPolicy.SOURCE 编译器使用后,直接丢弃这种策略的注释
② RetentionPolicy.CLASS 编译器将把注解记录在 class 文件中,当运行
Java 程序时,JVM 不会保留注释。这是默认值
③ RetentionPolicy.RUNTIME 编译器将把注解记录在 class 文件中,当运行
Java 程序时,JVM 会保留注释,程序可以通过反射获取该注解
2) @Target 注解
用于修饰 Annotation 定义,用于指定被修饰的 Annotation 能用于修饰哪些
程序元素。@Target 也包含一个名为 value 的成员变量。
3) @Documented 注解
用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档,
即在生成文档时,看到该注解
说明:定义为 Documented 的注解必须设置 Retention 值为 RUNTIME
4) @Inherited 注解
被它修饰的 Annotation 将具有继承性,如果某个类使用了被 @Inherited 修饰
的 Annotation ,则其子类将自动具有该注解
二、 Exception(异常)
代码出现异常/问题,可以使用 try-catch 异常处理机制来解决,从而保证程序的健壮性
解决方法:选择该代码块,alt + shift +z (idea是 ctrl+alt+t ),选中 try-catch,既可以继续执行
1.异常的概念
Java 语言中,将程序执行中发生的不正常情况成为 "异常"。
(开发过程中的语法错误和逻辑错误不是异常)
(2) 执行过程中所发生的的异常事件可分为两大类
① Error (错误):Java 虚拟机无法解决的严重问题
例如:JVM 系统内部错误、资源耗尽等严重情况;
StackOverflowError [栈溢出] 和 OOM (out of memory),
Error 是严重错误,程序会崩溃
② Exception:其他因编程错误或偶然的外在因素导致的一般性问题,
可以使用针对性的代码进行处理。
例如:空指针访问试图读取不存在的文件,网络连接中断等等
Exception 分为两大类:
运行时异常 [程序运行时,发生的异常]
编译时异常 [编程时,编译器检查出的异常]
2. 异常体系图
体现了继承和实现关系
① 异常分为两大类,运行时异常和编译时异常
② 运行时异常,编译器不要求强制处置的异常 (编译器检查不出来)。
一般是编程时的逻辑错误,是程序员应该避免其出现的异常
java.lang.RuntimeException 类及它的子类都是运行时异常
③ 对于运行时异常,可以不作处理,因为这类异常很普遍,若全处理可能会
对程序的可读性和运行效率产生影响
④ 编译时异常,是编译器要求必须处置的异常
3. 常见的运行时异常
① NullPointerException 空指针异常
② ArithmeticException 数学运算异常
③ ArrayIndexOutOfBoundsException 数组下标越界异常
④ ClassCastException 类型转换异常
⑤ NumberFormatException 数字格式不正确异常[]
4. 常见的编译异常
编译异常是指在编译期间,就必须处理的异常,否则代码不能通过编译
① SQLException 操作数据库时,查询表可能发生异常
② IQException 操作文件时,发生的异常
③ FileNotFoundException 当操作一个不存在的文件时,发生异常
④ ClassNotFoundException 加载类,而该类不存在时,异常
⑤ EOFException 操作文件,到文件末尾,发生异常
⑥ IllegalArguementException 参数异常
5. 异常处理的方式
异常处理就是当异常发生时,对异常处理的方式
① try-catch-finally
程序员在代码中捕获发生的异常,自行处理
try {
代码/可能有异常
} catch (Exception e) {
// 捕获到异常
// 当异常发生时,系统将异常封装成 Exception 对象 e,
// 传递给 catch,得到异常对象后,程序员自己处理
// 注:如果没有发生异常,catch 代码块不执行
// try-catch 块可以有多个
} finally{
// 不管 try 代码块是否有异常发生,始终要执行 finally
// 所以,通常将释放资源的代码,放在 finally
// 如果没有finally,语法也可以通过
}
② throws
将发生的异常抛出(甩锅),交给调用者 (方法) 来处理,最顶级的处理者就是JVM
(2) try-catch 注意事项
① 如果异常发生了,则异常发生后面的代码不会执行,直接进入到 catch 块
② 如果异常没有发生,则顺序执行 try 的代码块,不会进入到 catch
③ 如果希望不管是否发生异常,都执行某段代码(比如关闭链接,释放资源等)
则执行-finally{}
④ 可以有多个 catch 语句,捕获不同的异常(进行不同的业务处理),
要求父类异常在后,子类异常在前,
比如(Exception 在后,NullPointerException 在前),
如果发生异常,只会匹配一个 catch
⑤ 可以进行 try-finally 配合使用,这种用法相当于没有捕获异常,
因此程序会直接崩掉/退出。
应用场景,就是执行一段代码,不管是否发生异常,都必须执行
某个业务逻辑
public class Exception{
public static int method(){
int i = 1;
try{
i++; //i=2
String[] names = new String[3];
if (names[1].equals("tom")){//空指针
System.out.println(name[1]);
} else {
name[3] = "hahah";
}
return 1;
} catch (ArrayIndexOutOfBoundsException e){
return 2;
} catch (NullPointerException e){
return ++i; //i=3,保存临时变量 temp=3;
} finally {
++i; //i=4
System.out.println("i=" + i); //i=4
}
}
public static void main(String[] args){
System.out.println(method()); //3
} //i=4,3
(3) throws 异常处理
① 如果一个方法中的语句执行时,可能生成某种异常,但是并不能确定如何
处理这种异常,则此方法应显示地声明抛出异常,声明该方法将不对这些
异常进行处理,而由该方法的调用者负责处理
② 在方法声明中用 throws 语句可以申明抛出异常的列表,throws 后面的异常
类型可以是方法中产生的异常类型,也可以是它的父类
③ throws 关键字后面也可以是 异常列表,即可以抛出多个异常
注意事项:
① 对于编译异常,程序中必须处理,比如 try-catch 或 throws
② 对于运行时异常,程序中如果没有处理,默认就是 throws 的方式处理
③ 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的
异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型
④ 在 throws 过程中,如果有方法 try-catch,就相当于处理异常,就可以不必 throws
6. 自定义异常
当程序中出现了某些 "错误" ,但该错误信息并没有在 Throwable 子类中描述处理,
这个可以可以自己设计异常类,用于描述该错误信息
自定义异常的步骤:
① 定义类:自定义异常类名(程序员自己写) 继承 Exception 或 RuntimeException
② 如果继承 Exception ,属于编译异常
③ 如果继承 RuntimeException ,属于运行异常 (一般继承 RuntimeException)
public class CustomException {
public static void main(String[] args) {
int age = 180;
//要求范围在 18 – 120 之间,否则抛出一个自定义异常
if(!(age >= 18 && age <= 120)) {
//这里我们可以通过构造器,设置信息
throw new AgeException("年龄需要在 18~120 之间");
}
System.out.println("你的年龄范围正确.");
}
}
class AgeException extends RuntimeException {
public AgeException(String message) {//构造器
super(message);
}
}
7. throw 和 throws 的区别
意义 | 位置 | 后面跟的东西 | |
throws | 异常处理的一种方式 | 方法申明处 | 异常类型 |
throw | 手动生成异常对象的关键字 | 方法体中 | 异常对象 |