枚举
枚举也是数据类型:引用类型
在程序中需要定义一些明确的值:春天,夏天,秋天,冬天,使用枚举来完成
/*
* 1.7之前没办法通过switch 来判断字符串,可以使用枚举和switch搭配来完成,
* 1.7之后支持使用String类型来进行匹配,所以枚举的一些工作被String代替
*
* 语法:
* 访问权限修饰符 enum 枚举名{
* 具体的值(枚举常量)
* }
* 若有多个常量存在使用逗号隔开,在没有常量的后面还有其他实现,需要在其后面添加分号,否则可以不添加
*/
public enum WeekDay {
MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
/*
* 枚举的特点:
* 1.所有定义的枚举,底层实现都是一个类,这个类继承了所有枚举的父类Enum(不能被显式地继承)
* 2.枚举中是可以定义成员方法和抽象方法,成员变量的
* 3.每个枚举值都是一个静态常量
* 4.通过反编译可以看到枚举有一个隐藏的方法values 可以获取所有的枚举值
*/
}
import java.util.Random;
public class EnumDemo {
public static WeekDay getWeekDay(){
int num = new Random().nextInt(7)+1;
switch (num) {
case 1:
//枚举只能存储自身所定义的值,不能是其他值
//获取枚举值:枚举名.常量名
return WeekDay.MONDAY;
case 2:
return WeekDay.THURSDAY;
case 3:
return WeekDay.WEDNESDAY;
case 4:
return WeekDay.THURSDAY;
case 5:
return WeekDay.FRIDAY;
case 6:
return WeekDay.SATURDAY;
case 7:
return WeekDay.SUNDAY;
default:
return WeekDay.MONDAY;
}
}
public static void main(String[] args) {
//创建枚举对象
WeekDay weekDay = getWeekDay();
switch (weekDay) {
case MONDAY:
System.out.println("星期一");
break;
case TUESDAY:
System.out.println("星期二");
break;
case WEDNESDAY:
System.out.println("星期三");
break;
case THURSDAY:
System.out.println("星期四");
break;
case FRIDAY:
System.out.println("星期五");
break;
case SATURDAY:
System.out.println("星期六");
break;
case SUNDAY:
System.out.println("星期日");
break;
default:
break;
}
}
}
- 枚举扩展:
枚举在底层就是一个类,所以可以在枚举中定义属性方法:
@Getter
@ToString
public enum WeekDay {
MONDAY("0000", "MONDAY", "星期一"){
//无效代码
public void method1(){
System.out.println("enum WeekDay MONDAY.clazz method");
}
},
TUESDAY("0001", "TUESDAY", "星期二"){
//重写
public void method(){
System.out.println("enum WeekDay TUESDAY.clazz method");
}
};//WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
@Setter
private String code;
private String tag;
private String message;
//默认private
WeekDay(String code, String tag, String message) {
this.code = code;
this.tag = tag;
this.message = message;
}
public void method(){
System.out.println("WeekDay.clazz method");
}
public static void main(String[] args) {
//valueOf
System.out.println(MONDAY.valueOf("MONDAY"));//WeekDay.MONDAY(code=0000, tag=MONDAY, message=星期一)
System.out.println(TUESDAY.valueOf("MONDAY"));//WeekDay.MONDAY(code=0000, tag=MONDAY, message=星期一)
//values
System.out.println(Arrays.toString(MONDAY.values()));//[WeekDay.MONDAY(code=0000, tag=MONDAY, message=星期一), WeekDay.TUESDAY(code=0001, tag=TUESDAY, message=星期二)]
//属性
System.out.println(MONDAY.getCode());//0000
System.out.println(MONDAY.getTag());//MONDAY
System.out.println(MONDAY.getMessage());//星期一
System.out.println(MONDAY);//WeekDay.MONDAY(code=0000, tag=MONDAY, message=星期一)
//set get
MONDAY.setCode("1111");
System.out.println(MONDAY.getCode());//1111
//方法
MONDAY.method();//WeekDay.clazz method
// MONDAY.method1();
WeekDay.MONDAY.method();//WeekDay.clazz method
TUESDAY.method();//enum WeekDay TUESDAY.clazz method
}
}
异常
/*
* Throwable:所有异常的根类
* 1.Error:一般指JVM出现了一些不可修复的问题,如:内存溢出,系统崩溃
* Error是由JVM抛出来的,此类错误名字的最后一定有Error
* Error级别的错误,我们不处理(处理不了)
* 2.Exception:指程序中出现了不正常的情况,该问题可以被修复,名字后定有Exception
* 运行时异常 --> RuntimeException --> 程序在运行时出现的异常
* 编译时异常 --> Exception --> 写代码的时候出现的异常
* 特点:只要发生运行时异常,异常位置之后的的代码都不会执行
* 编译时异常会在书写代码时提示,编译时必须处理(不处理程序无法正常执行)
*
*/
- 捕获异常:
/*
* 捕获异常:
* try...catch (多应对一种异常)
* 异常处理:记录日志/打印异常信息/继续抛出异常
*/
public class Exception {
public static void main(String[] args) {
int x = 9;
int y = 0;
int result = 0;
try {
//抓取异常
result = x/y;
//不执行
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("出现异常");
/*
* 通过e来获取信息
* 这些方法
* getMessage() 获取异常的描述信息,发生异常原因
* toString() 获取异常的类型和异常信息的描述
* printStackTrace() 打印异常的跟踪栈信息并输出到控制台上
* 不需要使用System.out.println();
* 在开发和测试阶段使用,在项目上线的时候,所有的方法都进行替换和删除
*/
System.out.println(e.getMessage());
System.out.println(e.toString());
e.printStackTrace();
}
System.out.println("end......");
}
}
运行结果:
- 多异常抓取:
/*
* try...catch...catch 多异常抓取
* catch的个数不限,有多少抓多少
* 父类异常一定要放到最后一个catch中,不能放到最上面
*/
public class Demo {
public static void main(String[] args) {
System.out.println("begin.......");
int x = 9;
int y = 0;
String str = "123a";
int result = 0;
try {
int num = Integer.parseInt(str);
result = x/y;
System.out.println(result);
System.out.println(num);
}catch(ArithmeticException e) {
System.out.println(e.getMessage());
}catch(NumberFormatException e) {
System.out.println(e.toString());
}
System.out.println("end.......");
}
}
运行结果:
- 平行抓取:
/*
* 能不使用Exception抓取所有异常就不使用,实在不能确定异常类型时再使用
*
* JDK1.7提供的平行抓取:
* 通过 | 这个运算符来区分不同的异常
* 但是若这样抓取需要将父类异常放到子类异常之后
*/
try {
int num = Integer.parseInt(str);
result = x/y;
System.out.println(result);
System.out.println(num);
}catch(ArithmeticException | NumberFormatException e) {
System.out.println(e.getMessage());
}
- try...catch...finally:
/*
* try...catch...finally
* finally关键字:finally代码块
* ps:finally代码块无论异常发生与否,都会执行
* 一般作为释放资源用:IO,网络连接,数据库连接等,使用完之后需要释放资源
*
* 有一种扩展语句:try...finally
* 抛出异常不处理,finally用来进行资源释放
*/
当异常对象是Exception类(或其子类)的实例时,能通过Java虚拟机(无论是编译时异常还是运行时异常)或者throw语句抛出该异常对象,并能通过try...catch...finally处理
public class ExceptionTest {
public static int result1() {
int x = 9;
int y = 0;
int result = 0;
try {
result = x / y;
return result;
} catch (ArithmeticException e) {
return Integer.MAX_VALUE;
} finally {
System.out.println("先赋值再运算" + result++);
System.out.println(++result + "先运算再赋值");
System.out.println("finally语句块被执行了");
}
}
public static int result2() {
int x = 9;
int y = 3;
int result = 0;
try {
result = x / y;
return result;
} catch (ArithmeticException e) {
return Integer.MAX_VALUE;
} finally {
System.out.println("先赋值再运算" + result++);
System.out.println(++result + "先运算再赋值");
System.out.println("finally语句块被执行了");
}
}
public static int result3() {
try {
return 1;
} finally {
//如果finally中有return语句,永远返回finally中的结果
//此处有警告
return 100;
}
}
public static int result4() {
try {
return 1;
} catch (java.lang.Exception e) {
return 3;
} finally {
//如果finally中有return语句,永远返回finally中的结果
//此处有警告
return 100;
}
}
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE);
System.out.println("------------------------");
System.out.println(result1());
System.out.println("------------------------");
System.out.println(result2());
System.out.println("------------------------");
System.out.println(result3());
System.out.println("------------------------");
System.out.println(result4());
}
}
运行结果:
- throw:
能抓就别抛
/*
* throw:创建一个异常并抛出,在方法体中进行异常抛出
* 语法:throw new 异常类("异常信息")
* 在方法中使用等价于return 终止方法
* throw既可以抛出编译时异常,也可以抛出运行时异常
* 若抛出的是编译时异常,一般要再加throws,或者try...catch
*/
public class ExceptionTest {
public static void main(String[] args) {
String value = "123a";
System.out.println("start\n");
//运行时异常
//不处理
// int num = getNumber(value);
/*
Exception in thread "main" java.lang.NumberFormatException: 您输入的字符串不合法:123a
at demo.ExceptionTest.getNumber(ExceptionTest.java:30)
at demo.ExceptionTest.main(ExceptionTest.java:12)
*/
//处理
try {
int num1 = getNumber(value);
} catch (NumberFormatException e) {
System.out.println(e.getMessage());
}
//编译时异常
//必须处理
try {
int num2 = getNumberNeedDeel(value);
} catch (Exception e) {
System.out.println(e.getMessage());
}
//不必须处理
int num3 = getNumberSelfDeel(value);
System.out.println("\nend");
}
//抛出运行时异常
public static int getNumber(String value) {
try {
return new Integer(value).intValue();
} catch (NumberFormatException e) {
//此处打印无效,因为有返回值,所以需要返回一个异常对象
throw new NumberFormatException("您输入的字符串不合法:" + value);
//JDK1.7增强了throw,在不创建异常对象的前提下抛出异常
// throw e;
}
}
//抛出编译时异常
public static int getNumberNeedDeel(String value) throws Exception {
try {
return new Integer(value).intValue();
} catch (NumberFormatException e) {
throw new Exception("您输入的字符串不合法:" + value);//此处为编译时异常时要么throws要么try catch
}
}
//自处理编译时异常
public static int getNumberSelfDeel(String value) {
try {
try {
return new Integer(value).intValue();
} catch (NumberFormatException e) {
throw new Exception("您输入的字符串不合法:" + value);
}
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
}
运行结果:
- throws:
/*
* throws:
* 作用在方法上,若方法有异常发生,此时可以使用throws关键字将方法中出现异常抛出处理
*
* 在设计方法时,方法中会产生一些异常,但是这样写异常不应该在方法中处理而是需要在调用者来处理,
* 此时可以将当前方法中的异常抛出
* ps: throws可以无限的向上抛出,但是终点main中还抛出--> 直接就是JVM
* 若将所有异常都是用throws抛出,那么我们程序猿就失去作用
*/
public class Demo {
public static void main(String[] args) {
String value = "123a";
int num = getNumber(value);
}
public static int getNumber(String value)throws NumberFormatException{
return new Integer(value).intValue();
}
}
- throw和throws:
throw:运用在方法体内部,给调用者返回一个异常对象,和return一样可以结束方法
throws:运用于方法之上,表示当前方法异常不处理,提醒调用该方法者有异常未处理
若使用 throw 抛出是Exception类型异常(编译时异常),必须在方法上使用throws将异常抛出提示调用者
try-catch:发生异常时进入catch直接处理,处理后程序继续向下执行本方法代码
throws / try-finally:主要起提示作用,强制本方法调用者进行异常处理,发生异常时此方法内位于异常后代码不再执行,异常直接抛给调用本方法的上层进入上层编写的catch中处理
try-catch + throw-new-Exception() + (throws):发生异常时进入catch处理,处理后将创建的自定义异常抛给上层,方法内位于异常后代码编译时直接报unreachable;可用来做异常链;若throw的为编译时异常,方法签名也必须加上throws强制调用者处理异常,否则java会编译不通过,若为运行时异常,java不会强制写throws
- 自定义异常:
Java中提供非常丰富的异常类库,但是在某些时刻我们自己编译的代码中出现的问题,想使用异常进行提示,但是系统中的异常类库没有相似的,所以可以使用自定义异常来代替
若自定义异常带提示作用,在写代码时(编译时)就提示作者,那么自定异常就需要继承Exception
若自定异常只有运行时才会出现提示,那么自定义异常就需要继承RuntimeException
无论是继承谁实现都是相同的
/*
* 需求:定制一个桌子,桌子的半径[30.123~31.123]之间是合格的,否则提示不合格
*/
public class Demo {
public static void main(String[] args) {
Worker worker = new Worker("小明");
Desk desk = new Desk(32.14);
try {
checkDesk(desk);
} catch (DeskException e) {
System.out.println(e.getMessage());
}
}
public static void checkDesk(Desk desk) {
double r = desk.getR();
if(r >= 30.123 && r <= 31.123) {
System.out.println("合格");
}else {
throw new DeskException("制作不合格,不在规定范围内:"+r);
}
}
}
//工人类
class Worker{
private String name;
public Worker() {super();}
public Worker(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//做桌子
public Desk makeDesk(double r) {
return new Desk(r);
}
}
//桌子类
class Desk{
private double r;
public Desk() {super();}
public Desk(double r) {
super();
this.r = r;
}
public double getR() {
return r;
}
public void setR(double r) {
this.r = r;
}
}
//自定义异常类
class DeskException extends RuntimeException{
private static final long serialVersionUID = 1L;
public DeskException() {super();}
public DeskException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public DeskException(String message, Throwable cause) {
super(message, cause);
}
public DeskException(String message) {
super(message);
}
public DeskException(Throwable cause) {
super(cause);
}
}
- 异常链和异常转换:
异常链:把原始异常包装为异常类,从而形成一个多异常的排序序列,有助于查找异常发生的根本原因
异常转换:当前最上层的系统是不关心底层的异常细节时,可以将原有的异常进行包装,将他输出给上一层异常