接口,是Java语言中一种引用类型,是方法的集合。接口的内部主要就是封装了方法,包含抽象方法(JDK 7及之前),默认方法和静态方法(JDK 8),私有方法 (JDK 9)。前端
接口定义:java
它与定义类方式类似,可是使用 interface 关键字。它也会被编译成.class文件,但必定要明确它并非类,而是另一种引用数据类型。程序员
引用类型:数组、类、接口数据库
接口语法:编程
1 public interface 接口名称 { 2 // 常量 3 // 抽象方法 4 // 默认方法 5 // 静态方法 6 // 私有方法 7 }
接口当中也能够定义“成员变量”,可是必须使用public static final三个关键字进行修饰。从效果上看,这其实就是接口的【常量】。数组
语法编程语言
1 public static final 数据类型 常量名称 = 数据值;
备注:一旦使用final关键字进行修饰,说明不可改变。ide
注意事项:ui
1. 接口当中的常量,能够省略public static final,注意:不写也照样是这样。spa
2. 接口当中的常量,必须进行赋值;不能不赋值。
3. 接口中常量的名称,使用彻底大写的字母,用下划线进行分隔。(推荐命名规则)
抽象方法:使用 abstract 关键字修饰,能够省略,没有方法体。该方法供子类实现使用。
语法:
1 public interface InterFaceName { 2 public abstract void method(); 3 }
默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。
语法:
1 public interface InterFaceName { 2 public default void method() { 3 // 执行语句 4 } 5 }
备注:接口当中的默认方法,能够解决接口升级的问题。及能够后期进行重写升级。
静态方法:使用 static 修饰,供接口直接调用。
1 public interface InterFaceName { 2 public static void method2() { 3 // 执行语句 4 } 5 }
普通私有方法:解决多个默认方法之间重复代码问题。
格式
1 private 返回值类型 方法名称(参数列表) { 2 方法体 3 }
1 public interface MyInterfacePrivateA { 2 3 public default void methodDefault1() { 4 System.out.println("默认方法1"); 5 methodCommon(); 6 } 7 8 public default void methodDefault2() { 9 System.out.println("默认方法2"); 10 methodCommon(); 11 } 12 13 // 普通私有方法 14 private void methodCommon() { 15 System.out.println("AAA"); 16 System.out.println("BBB"); 17 System.out.println("CCC"); 18 } 19 20 }
静态私有方法:解决多个静态方法之间重复代码问题
格式
1 private static 返回值类型 方法名称(参数列表) { 2 方法体 3 }
1 public interface MyInterfacePrivateB { 2 3 public static void methodStatic1() { 4 System.out.println("静态方法1"); 5 methodStaticCommon(); 6 } 7 8 public static void methodStatic2() { 9 System.out.println("静态方法2"); 10 methodStaticCommon(); 11 } 12 13 private static void methodStaticCommon() { 14 System.out.println("AAA"); 15 System.out.println("BBB"); 16 System.out.println("CCC"); 17 } 18 19 }
接口使用步骤:
1. 接口不能直接使用,必须有一个“实现类”来“实现”该接口。
格式:
1 public class 实现类名称 implements 接口名称 { 2 // ... 3 }
2. 接口的实现类必须覆盖重写(实现)接口中全部的抽象方法。实现:去掉abstract关键字,加上方法体大括号。
3. 建立实现类的对象,进行使用。
接口中的常量使用只须要:接口名.常量名。不须要建立对象
1 public interface MyInterfaceConst { 2 // 这其实就是一个常量,一旦赋值,不能够修改 3 public static final int NUM_OF_MY_CLASS = 12; 4 5 } 6 7 8 -------------------------------------------------------------------------------- 9 public static void main(String[] args) { 10 // 访问接口当中的常量 11 System.out.println(MyInterfaceConst.NUM_OF_MY_CLASS); 12 }
1. 接口的默认方法,能够经过接口实现类【对象】,直接调用。
2. 接口的默认方法,也能够被接口实现类进行覆盖重写。
1 public interface MyInterfaceDefault { 2 // 默认方法 3 public default void methodDefault() { 4 System.out.println("这是默认方法"); 5 } 6 } 7 8 9 10 ---------------------------------------------------------------- 11 // 在实现类中能够对默认方法进行覆盖重写,也能够什么操做都不作 12 // 可是若是想使用默认方法必需要有实现类 13 public class MyInterfaceDefaultA implements MyInterfaceDefault { 14 // 能够对默认方法覆盖重写 15 } 16 17 18 -------------------------------------------------------------------------- 19 public class Demo02Interface { 20 21 public static void main(String[] args) { 22 // 建立了实现类对象 23 MyInterfaceDefaultA a = new MyInterfaceDefaultA(); 24 25 // 调用默认方法,若是实现类当中没有,会向上找接口 26 a.methodDefault(); // 这是默认方法 27 28 } 29 }
静态方法的使用:接口名.静态方法名(参数);
注意:不能经过接口实现类的对象来调用接口当中的静态方法。
1 public interface MyInterfaceStatic { 2 3 public static void methodStatic() { 4 System.out.println("这是接口的静态方法!"); 5 } 6 } 7 8 9 10 ------------------------------------------------------------------ 11 // 实现类 12 public class MyInterfaceStaticImpl implements MyInterfaceStatic { 13 14 } 15 16 17 --------------------------------------------------------------------------- 18 /* 19 注意事项:不能经过接口实现类的对象来调用接口当中的静态方法。 20 正确用法:经过接口名称,直接调用其中的静态方法。 21 格式: 22 接口名称.静态方法名(参数); 23 */ 24 public class Demo03Interface { 25 26 public static void main(String[] args) { 27 // 建立了实现类对象 28 MyInterfaceStaticImpl impl = new MyInterfaceStaticImpl(); 29 30 // 错误写法! 31 // impl.methodStatic(); 32 33 // 直接经过接口名称调用静态方法 34 MyInterfaceStatic.methodStatic(); 35 } 36 }
在实现类中覆盖重写抽象方法。而后建立实现类【对象】调用实现的方法。
1 /* 2 注意事项: 3 1. 接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract 4 2. 这两个关键字修饰符,能够选择性地省略。(今天刚学,因此不推荐。) 5 3. 方法的三要素,能够随意定义。 6 */ 7 public interface MyInterfaceAbstract { 8 9 // 这是一个抽象方法 10 public abstract void methodAbs1(); 11 12 // 这也是抽象方法 13 abstract void methodAbs2(); 14 15 // 这也是抽象方法 16 public void methodAbs3(); 17 18 // 这也是抽象方法 19 void methodAbs4(); 20 } 21 22 23 ------------------------------------------------------------------------- 24 public class MyInterfaceAbstractImpl implements MyInterfaceAbstract { 25 @Override 26 public void methodAbs1() { 27 System.out.println("这是第一个方法!"); 28 } 29 30 @Override 31 public void methodAbs2() { 32 System.out.println("这是第二个方法!"); 33 } 34 35 @Override 36 public void methodAbs3() { 37 System.out.println("这是第三个方法!"); 38 } 39 40 @Override 41 public void methodAbs4() { 42 System.out.println("这是第四个方法!"); 43 } 44 } 45 46 47 48 ----------------------------------------------------------------- 49 /* 50 注意事项: 51 若是实现类并无覆盖重写接口中全部的抽象方法,那么这个实现类本身就必须是抽象类。 52 */ 53 public class Demo01Interface { 54 55 public static void main(String[] args) { 56 // 错误写法!不能直接new接口对象使用。 57 // MyInterfaceAbstract inter = new MyInterfaceAbstract(); 58 59 // 建立实现类的对象使用 60 MyInterfaceAbstractImpl impl = new MyInterfaceAbstractImpl(); 61 impl.methodAbs1(); 62 impl.methodAbs2(); 63 } 64 }
注意事项:若是实现类并无覆盖重写接口中全部的抽象方法,那么这个实现类本身就必须是抽象类。
普通私有方法:只有在其接口中的默认方法能够调用。
私有静态方法:只有在其接口中的默认方法和静态方法能够调用。
若是一个接口中有多个默认方法,而且方法中有重复的内容,那么能够抽取出来,封装到私有方法中,供默认方法去调用。从设计的角度讲,私有的方法是对默认方法和静态方法的辅助
在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是能够实现多个接口的,这叫作接口的多实现。而且,一个类能继承一个父类,同时实现多个接口。
语法
1 class 类名 [extends 父类名] implements 接口名1,接口名2,接口名3... { 2 // 重写接口中抽象方法【必须】 3 // 重写接口中默认方法【不重名时可选】 4 }
接口中,有多个抽象方法时,实现类必须重写全部抽象方法。若是抽象方法有重名的,只须要重写一次。
1 public interface MyInterfaceA { 2 3 public abstract void methodA(); 4 5 public abstract void methodAbs(); 6 7 } 8 9 10 11 ------------------------------------------------------- 12 public interface MyInterfaceB { 13 14 public abstract void methodB(); 15 16 public abstract void methodAbs(); 17 18 } 19 20 21 22 ------------------------------------------------------------ 23 public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB { 24 25 @Override 26 public void methodA() { 27 System.out.println("覆盖重写了A方法"); 28 } 29 30 31 @Override 32 public void methodB() { 33 System.out.println("覆盖重写了B方法"); 34 } 35 36 // 重名的只须要重写一次 37 @Override 38 public void methodAbs() { 39 System.out.println("覆盖重写了AB接口都有的抽象方法"); 40 } 41 }
注意:若是实现类没有覆盖重写全部接口当中的全部抽象方法,那么实现类就必须是一个抽象类。
接口中,有多个默认方法时,实现类均可继承使用。不重名的能够不重写。若是默认方法有重名的,必须重写一次。
1 public interface MyInterfaceA { 2 3 public default void methodDefault() { 4 System.out.println("默认方法AAA"); 5 } 6 } 7 8 9 10 --------------------------------------------------- 11 public interface MyInterfaceB { 12 13 public default void methodDefault() { 14 System.out.println("默认方法BBB"); 15 } 16 17 } 18 19 20 21 ------------------------------------------------------- 22 public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB { 23 // 两个接口中重名。必须重写 24 @Override 25 public void methodDefault() { 26 System.out.println("对多个接口当中冲突的默认方法进行了覆盖重写"); 27 } 28 }
接口中,存在同名的静态方法并不会冲突,缘由是只能经过各自接口名访问静态方法。
一个类若是直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。
一个接口能继承另外一个或者多个接口,这和类之间的继承比较类似。接口的继承使用 extends 关键字,子接口继承父接口的方法。
1 // 接口A 2 public interface MyInterfaceA { 3 4 public abstract void methodA(); 5 6 public abstract void methodCommon(); 7 8 public default void methodDefault() { 9 System.out.println("AAA"); 10 } 11 } 12 13 14 15 ---------------------------------------------------------- 16 // 接口B 17 public interface MyInterfaceB { 18 19 public abstract void methodB(); 20 21 public abstract void methodCommon(); 22 23 public default void methodDefault() { 24 System.out.println("BBB"); 25 } 26 } 27 28 29 30 -------------------------------------------------------------- 31 // 继承接口A和B的接口 32 /* 33 这个子接口当中有几个方法?答:4个。 34 methodA 来源于接口A 35 methodB 来源于接口B 36 methodCommon 同时来源于接口A和B 37 method 来源于我本身 38 */ 39 public interface MyInterface extends MyInterfaceA, MyInterfaceB { 40 41 public abstract void method(); 42 43 @Override 44 public default void methodDefault() { 45 46 } 47 } 48 49 50 ---------------------------------------------------------------------- 51 // 实现类 52 53 public class MyInterfaceImpl implements MyInterface { 54 @Override 55 public void method() { 56 57 } 58 59 @Override 60 public void methodA() { 61 62 } 63 64 @Override 65 public void methodB() { 66 67 } 68 69 @Override 70 public void methodCommon() { 71 72 } 73 }
注意事项:
1. 多个父接口当中的抽象方法若是重复,不要紧。
2. 多个父接口当中的默认方法若是重复,那么子接口必须进行默认方法的覆盖重写,【并且带着default关键字】。
在Java等面向对象的编程语言中,异常自己是一个类,产生异常就是建立异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理。
注意:异常指的并非语法错误,语法错了,编译不经过,不会产生字节码文件,根本不能运行.
Exception
Throwable中的经常使用方法:
public void printStackTrace():打印异常的详细信息。
包含了异常的类型,异常的缘由,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。*
public String getMessage():获取发生异常的缘由。
提示给用户的时候,就提示错误缘由。
public String toString():获取异常的类型和异常描述信息(不用)。
2,须要将这个异常对象告知给调用者。怎么告知呢?怎么将这个异常对象传递到调用者处呢?经过关键字throw就能够完成。throw 异常对象。
1 throw new 异常类名(参数); 2 示例: 3 throw new NullPointerException("要访问的arr数组不存在"); 4 5 throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");
注意:
1.throw关键字必须写在方法的内部
2.throw关键字后边new的对象必须是Exception或者Exception的子类对象
3.throw关键字抛出指定的异常对象,咱们就必须处理这个异常对象
throw关键字后边建立的是RuntimeException或者是 RuntimeException的子类对象,咱们能够不处理,默认交给JVM处理(打印异常对象并中断程序)
throw关键字后边建立的是编译异常(写代码的时候报错),咱们就必须处理这个异常,要么throws,要么try...catch
1 public class Demo03Throw { 2 public static void main(String[] args) { 3 //int[] arr = null; 4 int[] arr = new int[3]; 5 int e = getElement(arr,3); 6 System.out.println(e); 7 } 8 /* 9 定义一个方法,获取数组指定索引处的元素 10 参数: 11 int[] arr 12 int index 13 之后(工做中)咱们首先必须对方法传递过来的参数进行合法性校验 14 若是参数不合法,那么咱们就必须使用抛出异常的方式,告知方法的调用者,传递的参数有问题 15 注意: 16 NullPointerException是一个运行期异常,咱们不用处理,默认交给JVM处理 17 ArrayIndexOutOfBoundsException是一个运行期异常,咱们不用处理,默认交给JVM处理 18 */ 19 public static int getElement(int[] arr,int index){ 20 /* 21 咱们能够对传递过来的参数数组,进行合法性校验 22 若是数组arr的值是null 23 那么咱们就抛出空指针异常,告知方法的调用者"传递的数组的值是null" 24 */ 25 if(arr == null){ 26 throw new NullPointerException("传递的数组的值是null"); 27 } 28 29 /* 30 咱们能够对传递过来的参数index进行合法性校验 31 若是index的范围不在数组的索引范围内 32 那么咱们就抛出数组索引越界异常,告知方法的调用者"传递的索引超出了数组的使用范围" 33 */ 34 if(index<0 || index>arr.length-1){ 35 throw new ArrayIndexOutOfBoundsException("传递的索引超出了数组的使用范围"); 36 } 37 38 int ele = arr[index]; 39 return ele; 40 } 41 }
源码中对throw的使用示例:Object中的方法查看引用对象是否为null
1 //Obects类中的静态方法 2 //public static <T> T requireNonNull(T obj):查看指定引用对象不是null。 3 源码: 4 public static <T> T requireNonNull(T obj) { 5 if (obj == null){ 6 throw new NullPointerException(); 7 } 8 return obj; 9 }
1 import java.util.Objects; 2 3 public class Demo04Objects { 4 public static void main(String[] args) { 5 method(null); 6 } 7 8 public static void method(Object obj){ 9 //对传递过来的参数进行合法性判断,判断是否为null 10 // if(obj == null){ 11 // throw new NullPointerException("传递的对象的值是null"); 12 // } 13 14 //Objects.requireNonNull(obj); 15 Objects.requireNonNull(obj,"传递的对象的值是null"); 16 } 17 }
throws关键字:异常处理的第一种方式,交给别人处理
做用:
当方法内部抛出异常对象的时候,那么咱们就必须处理这个异常对象
可使用throws关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理(本身不处理,给别人处理),最终交给JVM处理-->中断处理
使用格式:(方法声明的时候使用)
1 修饰符 返回值类型 方法名(参数列表) throws AAAExcepiton,BBBExcepiton...{ 2 throw new AAAExcepiton("产生缘由"); 3 throw new BBBExcepiton("产生缘由"); 4 ... 5 }
注意:
1.throws关键字必须写在方法声明处
2.throws关键字后边声明的异常必须是Exception或者是Exception的子类
3.方法内部若是抛出了多个异常对象,那么throws后边必须也声明多个异常
若是抛出的多个异常对象有子父类关系,那么直接声明父类异常便可
4.调用了一个声明抛出异常的方法,咱们就必须的处理声明的异常
1)要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM
2)要么try...catch本身处理异常
1 import java.io.FileNotFoundException; 2 import java.io.IOException; 3 4 public class Demo05Throws { 5 /* 6 FileNotFoundException extends IOException extends Excepiton 7 若是抛出的多个异常对象有子父类关系,那么直接声明父类异常便可 8 */ 9 //public static void main(String[] args) throws FileNotFoundException,IOException { 10 //public static void main(String[] args) throws IOException { 11 public static void main(String[] args) throws Exception { 12 readFile("c:\\a.tx"); 13 14 System.out.println("后续代码"); 15 } 16 17 /* 18 定义一个方法,对传递的文件路径进行合法性判断 19 若是路径不是"c:\\a.txt",那么咱们就抛出文件找不到异常对象,告知方法的调用者 20 注意: 21 FileNotFoundException是编译异常,抛出了编译异常,就必须处理这个异常 22 可使用throws继续声明抛出FileNotFoundException这个异常对象,让方法的调用者处理 23 */ 24 public static void readFile(String fileName) throws FileNotFoundException,IOException{ 25 if(!fileName.equals("c:\\a.txt")){ 26 throw new FileNotFoundException("传递的文件路径不是c:\\a.txt"); 27 } 28 29 /* 30 若是传递的路径,不是.txt结尾 31 那么咱们就抛出IO异常对象,告知方法的调用者,文件的后缀名不对 32 */ 33 if(!fileName.endsWith(".txt")){ 34 throw new IOException("文件的后缀名不对"); 35 } 36 37 System.out.println("路径没有问题,读取文件"); 38 } 39 }
try...catch:异常处理的第二种方式,本身处理异常
格式:
1 try{ 2 可能产生异常的代码 3 }catch(定义一个异常的变量,用来接收try中抛出的异常对象){ 4 异常的处理逻辑,异常异常对象以后,怎么处理异常对象 5 通常在工做中,会把异常的信息记录到一个日志中 6 } 7 ... 8 catch(异常类名 变量名){ 9 10 }
注意:
1.try中可能会抛出多个异常对象,那么就可使用多个catch来处理这些异常对象
2.若是try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try...catch以后的代码
若是try中没有产生异常,那么就不会执行catch中异常的处理逻辑,执行完try中的代码,继续执行try...catch以后的代码
打印错误信息的经常使用方法:
public void printStackTrace():打印异常的详细信息。
包含了异常的类型,异常的缘由,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。*
public String getMessage():获取发生异常的缘由。
提示给用户的时候,就提示错误缘由。
public String toString():获取异常的类型和异常描述信息(不用)。
1 import java.io.IOException; 2 3 public class Demo01TryCatch { 4 public static void main(String[] args) { 5 try{ 6 //可能产生异常的代码 7 readFile("d:\\a.tx"); 8 System.out.println("资源释放"); 9 }catch (IOException e){//try中抛出什么异常对象,catch就定义什么异常变量,用来接收这个异常对象 10 //异常的处理逻辑,异常异常对象以后,怎么处理异常对象 11 //System.out.println("catch - 传递的文件后缀不是.txt"); 12 13 /* 14 Throwable类中定义了3个异常处理的方法 15 String getMessage() 返回此 throwable 的简短描述。 16 String toString() 返回此 throwable 的详细消息字符串。 17 void printStackTrace() JVM打印异常对象,默认此方法,打印的异常信息是最全面的 18 */ 19 //System.out.println(e.getMessage());//文件的后缀名不对 20 //System.out.println(e.toString());//重写Object类的toString java.io.IOException: 文件的后缀名不对 21 //System.out.println(e);//java.io.IOException: 文件的后缀名不对 22 23 24 // e.printStackTrace(); 25 /* 26 java.io.IOException: 文件的后缀名不对 27 at com.itheima.demo02.Exception.Demo01TryCatch.readFile(Demo01TryCatch.java:55) 28 at com.itheima.demo02.Exception.Demo01TryCatch.main(Demo01TryCatch.java:27) 29 */ 30 31 } 32 System.out.println("后续代码"); 33 } 34 35 /* 36 若是传递的路径,不是.txt结尾 37 那么咱们就抛出IO异常对象,告知方法的调用者,文件的后缀名不对 38 */ 39 public static void readFile(String fileName) throws IOException { 40 41 if(!fileName.endsWith(".txt")){ 42 throw new IOException("文件的后缀名不对"); 43 } 44 45 System.out.println("路径没有问题,读取文件"); 46 } 47 } 48 49
格式:
1 try{ 2 可能产生异常的代码 3 }catch(定义一个异常的变量,用来接收try中抛出的异常对象){ 4 异常的处理逻辑,异常异常对象以后,怎么处理异常对象 5 通常在工做中,会把异常的信息记录到一个日志中 6 } 7 ... 8 catch(异常类名 变量名){ 9 10 }finally{ 11 不管是否出现异常都会执行 12 }
注意:
1,finally不能单独使用,必须和try一块儿使用
2,finally通常用于资源释放(资源回收),不管程序是否出现异常,最后都要资源释放(IO)
3,当只有在try或者catch中调用退出JVM的相关方法,此时finally才不会执行,不然finally永远会执行
1 import java.io.IOException; 2 3 public class Demo02TryCatchFinally { 4 public static void main(String[] args) { 5 try { 6 //可能会产生异常的代码 7 readFile("c:\\a.tx"); 8 } catch (IOException e) { 9 //异常的处理逻辑 10 e.printStackTrace(); 11 } finally { 12 //不管是否出现异常,都会执行 13 System.out.println("资源释放"); 14 } 15 } 16 17 /* 18 若是传递的路径,不是.txt结尾 19 那么咱们就抛出IO异常对象,告知方法的调用者,文件的后缀名不对 20 21 */ 22 public static void readFile(String fileName) throws IOException { 23 24 if(!fileName.endsWith(".txt")){ 25 throw new IOException("文件的后缀名不对"); 26 } 27 28 System.out.println("路径没有问题,读取文件"); 29 } 30 }
注意1:多个异常使用捕获又该如何处理呢?
1. 多个异常分别处理。
2. 多个异常一次捕获,屡次处理。【推荐】
3. 多个异常一次捕获一次处理。
1 import java.util.List; 2 3 public class Demo01Exception { 4 public static void main(String[] args) { 5 /* 6 多个异常使用捕获又该如何处理呢? 7 1. 多个异常分别处理。 8 2. 多个异常一次捕获,屡次处理。 9 3. 多个异常一次捕获一次处理。 10 */ 11 12 //1. 多个异常分别处理。 13 try { 14 int[] arr = {1,2,3}; 15 System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 16 }catch (ArrayIndexOutOfBoundsException e){ 17 System.out.println(e); 18 } 19 20 try{ 21 List<Integer> list = List.of(1, 2, 3); 22 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 23 }catch (IndexOutOfBoundsException e){ 24 System.out.println(e); 25 } 26 27 28 //2. 多个异常一次捕获,屡次处理。 29 try { 30 int[] arr = {1,2,3}; 31 //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 32 List<Integer> list = List.of(1, 2, 3); 33 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 34 }catch (ArrayIndexOutOfBoundsException e){ 35 System.out.println(e); 36 }catch (IndexOutOfBoundsException e){ 37 System.out.println(e); 38 } 39 40 /* 41 一个try多个catch注意事项: 42 catch里边定义的异常变量,若是有子父类关系,那么子类的异常变量必须写在上边,不然就会报错 43 ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException 44 */ 45 try { 46 int[] arr = {1,2,3}; 47 //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 48 List<Integer> list = List.of(1, 2, 3); 49 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 50 }catch (IndexOutOfBoundsException e){ 51 System.out.println(e); 52 }catch (ArrayIndexOutOfBoundsException e){ 53 System.out.println(e); 54 } 55 56 //3. 多个异常一次捕获一次处理。 57 try { 58 int[] arr = {1,2,3}; 59 //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 60 List<Integer> list = List.of(1, 2, 3); 61 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 62 }catch (Exception e){ 63 System.out.println(e); 64 } 65 } 66 }
注意2:运行时异常被抛出能够不处理。即不捕获也不声明抛出。
默认给虚拟机处理,终止程序,何时不抛出运行时异常了,在来继续执行程序
1 import java.util.List; 2 3 public class Demo01Exception { 4 public static void main(String[] args) { 5 6 //运行时异常被抛出能够不处理。即不捕获也不声明抛出。 7 //默认给虚拟机处理,终止程序,何时不抛出运行时异常了,在来继续执行程序 8 int[] arr = {1,2,3}; 9 System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 10 List<Integer> list = List.of(1, 2, 3); 11 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 12 13 System.out.println("后续代码!"); 14 } 15 }
注意3:若是finally有return语句,永远返回finally中的结果,避免该状况.
1 public class Demo02Exception { 2 public static void main(String[] args) { 3 int a = getA(); 4 System.out.println(a);// 100 5 } 6 7 //定义一个方法,返回变量a的值 8 public static int getA(){ 9 int a = 10; 10 try{ 11 return a; 12 }catch (Exception e){ 13 System.out.println(e); 14 }finally { 15 //必定会执行的代码 16 a = 100; 17 return a; 18 } 19 } 20 }
注意4:子父类的异常:
若是父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出
1 public class Fu { 2 public void show01() throws NullPointerException,ClassCastException{} 3 public void show02() throws IndexOutOfBoundsException{} 4 public void show03() throws IndexOutOfBoundsException{} 5 public void show04() throws Exception {} 6 } 7 8 class Zi extends Fu{ 9 //子类重写父类方法时,抛出和父类相同的异常 10 public void show01() throws NullPointerException,ClassCastException{} 11 12 //子类重写父类方法时,抛出父类异常的子类 13 public void show02() throws ArrayIndexOutOfBoundsException{} 14 15 //子类重写父类方法时,不抛出异常 16 public void show03() {} 17 18 /* 19 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。 20 */ 21 //public void show04() throws Exception{} 22 23 //此时子类产生该异常,只能捕获处理,不能声明抛出 24 public void show04() { 25 try { 26 throw new Exception("编译期异常"); 27 } catch (Exception e) { 28 e.printStackTrace(); 29 } 30 } 31 }
为何要自定义异常:
咱们说了Java中不一样的异常类,分别表示着某一种具体的异常状况,那么在开发中老是有些异常状况是SUN没有定义好的,此时咱们根据本身业务的异常状况来定义异常类。例如年龄负数问题,考试成绩负数问题等等。
在开发中根据本身业务的异常状况来定义异常类.
自定义一个业务逻辑异常: RegisterException。一个注册异常类。
自定义一个编译期异常: 自定义类 并继承于java.lang.Exception
。
自定义一个运行时期的异常类:自定义类 并继承于java.lang.RuntimeException
。
语法:
1 public class XXXExcepiton extends Exception | RuntimeException{ 2 添加一个空参数的构造方法 3 添加一个带异常信息的构造方法 4 }
注意:
1.自定义异常类通常都是以Exception结尾,说明该类是一个异常类
2.自定义异常类,必须的继承Exception或者RuntimeException
继承Exception:那么自定义的异常类就是一个编译期异常,若是方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try...catch
继承RuntimeException:那么自定义的异常类就是一个运行期异常,无需处理,交给虚拟机处理(中断处理)
1 public class RegisterException extends /*Exception*/ RuntimeException{ 2 //添加一个空参数的构造方法 3 public RegisterException(){ 4 super(); 5 } 6 7 /* 8 添加一个带异常信息的构造方法 9 查看源码发现,全部的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息 10 */ 11 public RegisterException(String message){ 12 super(message); 13 } 14 }
自定义异常的使用语法和系统提供的使用语法相同:
1 public class RegisterException extends /*Exception*/ RuntimeException{ 2 //添加一个空参数的构造方法 3 public RegisterException(){ 4 super(); 5 } 6 7 /* 8 添加一个带异常信息的构造方法 9 查看源码发现,全部的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息 10 */ 11 public RegisterException(String message){ 12 super(message); 13 } 14 } 15 16 17 ======================================== 18 import java.util.Scanner; 19 20 /* 21 要求:咱们模拟注册操做,若是用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。 22 23 分析: 24 1.使用数组保存已经注册过的用户名(数据库) 25 2.使用Scanner获取用户输入的注册的用户名(前端,页面) 26 3.定义一个方法,对用户输入的中注册的用户名进行判断 27 遍历存储已经注册过用户名的数组,获取每个用户名 28 使用获取到的用户名和用户输入的用户名比较 29 true: 30 用户名已经存在,抛出RegisterException异常,告知用户"亲,该用户名已经被注册"; 31 false: 32 继续遍历比较 33 若是循环结束了,尚未找到重复的用户名,提示用户"恭喜您,注册成功!"; 34 */ 35 public class Demo01RegisterException { 36 // 1.使用数组保存已经注册过的用户名(数据库) 37 static String[] usernames = {"张三","李四","王五"}; 38 39 public static void main(String[] args) /*throws RegisterException*/ { 40 //2.使用Scanner获取用户输入的注册的用户名(前端,页面) 41 Scanner sc = new Scanner(System.in); 42 System.out.println("请输入您要注册的用户名:"); 43 String username = sc.next(); 44 checkUsername(username); 45 46 } 47 48 //3.定义一个方法,对用户输入的中注册的用户名进行判断 49 public static void checkUsername(String username) /*throws RegisterException*/ { 50 //遍历存储已经注册过用户名的数组,获取每个用户名 51 for (String name : usernames) { 52 //使用获取到的用户名和用户输入的用户名比较 53 if(name.equals(username)){ 54 //true:用户名已经存在,抛出RegisterException异常,告知用户"亲,该用户名已经被注册"; 55 try { 56 throw new RegisterException("亲,该用户名已经被注册"); 57 } catch (RegisterException e) { 58 e.printStackTrace(); 59 return; //结束方法 60 } 61 } 62 } 63 //若是循环结束了,尚未找到重复的用户名,提示用户"恭喜您,注册成功!"; 64 System.out.println("恭喜您,注册成功!"); 65 } 66 }
------------------------------