本文已参加[新人创造礼]活动,一同开启创造之路。
哈喽,咱们好!我是Why,一名在读学生,目前刚刚开端进入自己的编程学习生涯。虽然学习起步较晚,但我坚信做了才有0或1的或许。学了javaee一段时间今后也是选择在上分享自己的日常笔记,也希望能够在很多道友的咱们庭中浑然一体。 本文首要讲解java反常,假如咱们读后觉得有用的话,还请咱们多多支持博主:欢迎 ❤️点赞、收藏⭐、留言 ✨✨✨个人主页:JinHuan
反常
1、什么是反常,java供给反常处理机制有什么用?
以下程序履行进程中发生了不正常的状况,而这种不正常的状况叫做:反常
java言语是很完善的言语,供给了反常的处理办法,以下程序履行进程中呈现了不正常状况,
java把该反常信息打印输出到控制台,供程序员参阅。程序员看到反常信息之后,能够对
程序进行修改,让程序愈加的强健。
什么是反常:程序履行进程中的不正常状况。
反常的效果:增强程序的强健性。
2、以下程序履行控制台呈现了:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.bjpowernode.javase.exception.ExceptionTest01.main(ExceptionTest01.java:14)
这个信息被咱们称为:反常信息。这个信息是JVM打印的。
栗子
public class ExceptionTest01 {
public static void main(String[] args) {
int a = 10;
int b = 0;
// 实践上JVM在履行到此处的时分,会new反常目标:new ArithmeticException("/ by zero");
// 并且JVM将new的反常目标抛出,打印输出信息到控制台了。
int c = a / b;
System.out.println(a + "/" + b + "=" + c);
// 此处运行也会创立一个:ArithmeticException类型的反常目标。
//System.out.println(100 / 0);
// 我观察到反常信息之后,对程序进行修改,愈加强健。
/*
int a = 10;
int b = 2;
if(b == 0) {
System.out.println("除数不能为0");
return;
}
// 程序履行到此处表示除数必定不是0
int c = a / b;
System.out.println(a + "/" + b + "=" + c);
*/
}
}
反常的存在办法
1、反常在java中以类的办法存在,每一个反常类都能够创立反常目标。
2、反常对应的现实生活中是怎样的?
火灾(反常类):
2008年8月8日,小明家着火了(反常目标)
2008年8月9日,小刚家着火了(反常目标)
2008年9月8日,小红家着火了(反常目标)
类是:模板。
目标是:实践存在的个别。
钱包丢了(反常类):
2008年1月8日,小明的钱包丢了(反常目标)
2008年1月9日,小芳的钱包丢了(反常目标)
栗子
public class ExceptionTest02 {
public static void main(String[] args) {
// 经过“反常类”实例化“反常目标”
NumberFormatException nfe = new NumberFormatException("数字格式化反常!");
// java.lang.NumberFormatException: 数字格式化反常!
System.out.println(nfe);
// 经过“反常类”创立“反常目标”
NullPointerException npe = new NullPointerException("空指针反常发生了!");
//java.lang.NullPointerException: 空指针反常发生了!
System.out.println(npe);
}
}
运行时反常实例
public class ExceptionTest03 {
public static void main(String[] args) {
/*
程序履行到此处发生了ArithmeticException反常,
底层new了一个ArithmeticException反常目标,
然后抛出了,由于是main办法调用了100 / 0,
所以这个反常ArithmeticException抛给了main办法,
main办法没有处理,将这个反常主动抛给了JVM。
JVM终究终止程序的履行。
ArithmeticException 承继 RuntimeException,归于运行时反常。
在编写程序阶段不需求对这种反常进行预先的处理。
*/
System.out.println(100 / 0);
// 这儿的HelloWorld没有输出,没有履行。
System.out.println("Hello World!");
}
}
编译时反常的实例
/*
以下代码报错的原因是什么?
由于doSome()办法声明方位上运用了:throws ClassNotFoundException
而ClassNotFoundException是编译时反常。有必要编写代码时处理,没有处理
编译器报错。
*/
public class ExceptionTest04 {
public static void main(String[] args) {
// main办法中调用doSome()办法
// 由于doSome()办法声明方位上有:throws ClassNotFoundException
// 咱们在调用doSome()办法的时分有必要对这种反常进行预先的处理。
// 假如不处理,编译器就报错。
//编译器报错信息: Unhandled exception: java.lang.ClassNotFoundException
//doSome();
}
/**
* doSome办法在办法声明的方位上运用了:throws ClassNotFoundException
* 这个代码表示doSome()办法在履行进程中,有或许会呈现ClassNotFoundException反常。
* 叫做类没找到反常。这个反常直接父类是:Exception,所以ClassNotFoundException归于编译时反常。
* @throws ClassNotFoundException
*/
public static void doSome() throws ClassNotFoundException{
System.out.println("doSome!!!!");
}
}
反常的处理办法
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
处理反常的榜首种办法:
在办法声明的方位上运用throws关键字抛出,谁调用我这个办法,我就抛给谁。抛给调用者来处理。
这种处理反常的态度:上报。
处理反常的第二种办法:
运用try..catch句子对反常进行捕捉。
这个反常不会上报,自己把这个事儿处理了。
反常抛到此处为止,不再上抛了。
留意:
只需反常没有捕捉,选用上报的办法,此办法的后续代码不会履行。
其他需求留意,try句子块中的某一行呈现反常,该行后边的代码不会履行。
try..catch捕捉反常之后,后续代码能够履行。 */
"在今后的开发中,处理编译时反常,应该上报仍是捕捉呢,怎样选?
假如希望调用者来处理,选择throws上报。
其它状况运用捕捉的办法。
public class ExceptionTest06 {
" 一般不主张在main办法上运用throws,由于这个反常假如真实的发生了,必定会抛给JVM。JVM只有终止。
// 反常处理机制的效果便是增强程序的强健性。怎样能做到,反常发生了也不影响程序的履行。所以
// 一般main办法中的反常主张运用try..catch进行捕捉。main就不要持续上抛了。
/*
public static void main(String[] args) throws FileNotFoundException {
System.out.println("main begin");
m1();
System.out.println("main over");
}
*/
public static void main(String[] args) {
// 100 / 0这是算术反常,这个反常是运行时反常,你在编译阶段,能够处理,也能够不处理。编译器不论。
//System.out.println(100 / 0); // 不处理编译器也不论
// 你处理也能够。
/*
try {
System.out.println(100 / 0);
} catch(ArithmeticException e){
System.out.println("算术反常了!!!!");
}
*/
System.out.println("main begin");
try {
// try测验
m1();
// 以上代码呈现反常,直接进入catch句子块中履行。
System.out.println("hello world!");
} catch (FileNotFoundException e){ // catch后边的如同一个办法的形参。
// 这个分支中能够运用e引证,e引证保存的内存地址是那个new出来反常目标的内存地址。
// catch是捕捉反常之后走的分支。
// 在catch分支中干什么?处理反常。
System.out.println("文件不存在,或许路径过错,也或许该文件被删去了!");
System.out.println(e); //java.io.FileNotFoundException: D:course1-课学习办法.txt (体系找不到指定的路径。)
}
// try..catch把反常捉住之后,这儿的代码会持续履行。
System.out.println("main over");
}
private static void m1() throws FileNotFoundException {
System.out.println("m1 begin");
m2();
// 以上代码出反常,这儿是无法履行的。
System.out.println("m1 over");
}
// 抛其他不行,抛ClassCastException阐明你仍是没有对FileNotFoundException进行处理
//private static void m2() throws ClassCastException{
// 抛FileNotFoundException的父目标IOException,这样是能够的。由于IOException包含FileNotFoundException
//private static void m2() throws IOException {
// 这样也能够,由于Exception包含所有的反常。
//private static void m2() throws Exception{
// throws后边也能够写多个反常,能够运用逗号离隔。
//private static void m2() throws ClassCastException, FileNotFoundException{
private static void m2() throws FileNotFoundException {
System.out.println("m2 begin");
// 编译器报错原因是:m3()办法声明方位上有:throws FileNotFoundException
// 咱们在这儿调用m3()没有对反常进行预处理,所以编译报错。
// m3();
m3();
// 以上假如呈现反常,这儿是无法履行的!
System.out.println("m2 over");
}
private static void m3() throws FileNotFoundException {
// 调用SUN jdk中某个类的结构办法。
// 这个类还没有接触过,后期IO流的时分就知道了。
// 咱们仅仅凭借这个类学习一下反常处理机制。
// 创立一个输入流目标,该流指向一个文件。
/*
编译报错的原因是什么?
榜首:这儿调用了一个结构办法:FileInputStream(String name)
第二:这个结构办法的声明方位上有:throws FileNotFoundException
第三:经过类的承继结构看到:FileNotFoundException父类是IOException,IOException的父类是Exception,
终究得知,FileNotFoundException是编译时反常。
过错原因?编译时反常要求程序员编写程序阶段有必要对它进行处理,不处理编译器就报错。
*/
//new FileInputStream("D:course1-开课学习办法.txt");
// 咱们选用榜首种处理办法:在办法声明的方位上运用throws持续上抛。
// 一个办法体傍边的代码呈现反常之后,假如上报的话,此办法完毕。
new FileInputStream("D:course1-课学习办法.txt");
System.out.println("假如以上代码出反常,这儿会履行吗??????????????????不会!!!");
}
}
public class ExceptionTest05 {
// 榜首种处理办法:在办法声明的方位上持续运用:throws,来完结反常的持续上抛。抛给调用者。
// 上抛类似于推卸责任。(持续把反常传递给调用者。)
/*
public static void main(String[] args) throws ClassNotFoundException {
doSome();
}
*/
// 第二种处理办法:try..catch进行捕捉。
// 捕捉等于把反常拦下了,反常真实的处理了。(调用者是不知道的。)
public static void main(String[] args) {
try {
doSome();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void doSome() throws ClassNotFoundException{
System.out.println("doSome!!!!");
}
}
About Try-catch
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
深入try..catch
"1、catch后边的小括号中的类型能够是具体的反常类型,也能够是该反常类型的父类型。
"2、catch能够写多个。主张catch的时分,精确的一个一个处理。这样有利于程序的调试。
"3、catch写多个的时分,从上到下,有必要恪守从小到大。
public class ExceptionTest07 {
/*
public static void main(String[] args) throws Exception, FileNotFoundException, NullPointerException {
}
*/
/*public static void main(String[] args) throws Exception {
}*/
public static void main(String[] args) {
//编译报错
/*try {
FileInputStream fis = new FileInputStream("D:course2-JavaSEdocumentJavaSE进阶讲义JavaSE进阶-01-面向目标.pdf");
} catch(NullPointerException e) {
}*/
/*try {
FileInputStream fis = new FileInputStream("D:curse2-JavaSEdocumentJavaSE进阶讲义JavaSE进阶-01-面向目标.pdf");
System.out.println("以上呈现反常,这儿无法履行!");
} catch(FileNotFoundException e) {
System.out.println("文件不存在!");
}
System.out.println("hello world!");*/
/*try {
FileInputStream fis = new FileInputStream("D:curse2-JavaSEdocumentJavaSE进阶讲义JavaSE进阶-01-面向目标.pdf");
} catch(IOException e) { // 多态:IOException e = new FileNotFoundException();
System.out.println("文件不存在!");
}*/
/*try {
FileInputStream fis = new FileInputStream("D:curse2-JavaSEdocumentJavaSE进阶讲义JavaSE进阶-01-面向目标.pdf");
} catch(Exception e) { // 多态:Exception e = new FileNotFoundException();
System.out.println("文件不存在!");
}*/
/*try {
//创立输入流
FileInputStream fis = new FileInputStream("D:curse2-JavaSEdocumentJavaSE进阶讲义JavaSE进阶-01-面向目标.pdf");
//读文件
fis.read();
} catch(Exception e) { //所有的反常都走这个分支。
System.out.println("文件不存在!");
}*/
/*try {
//创立输入流
FileInputStream fis = new FileInputStream("D:curse2-JavaSEdocumentJavaSE进阶讲义JavaSE进阶-01-面向目标.pdf");
//读文件
fis.read();
} catch(FileNotFoundException e) {
System.out.println("文件不存在!");
} catch(IOException e){
System.out.println("读文件报错了!");
}*/
// 编译报错。
/*
try {
//创立输入流
FileInputStream fis = new FileInputStream("D:curse2-JavaSEdocumentJavaSE进阶讲义JavaSE进阶-01-面向目标.pdf");
//读文件
fis.read();
} catch(IOException e){
System.out.println("读文件报错了!");
} catch(FileNotFoundException e) {
System.out.println("文件不存在!");
}
*/
// JDK8的新特性!
try {
//创立输入流
FileInputStream fis = new FileInputStream("D:curse2-JavaSEdocumentJavaSE进阶讲义JavaSE进阶-01-面向目标.pdf");
// 进行数学运算
System.out.println(100 / 0); // 这个反常是运行时反常,编写程序时能够处理,也能够不处理。
} catch(FileNotFoundException | ArithmeticException | NullPointerException e) {
System.out.println("文件不存在?数学反常?空指针反常?都有或许!");
}
}
}
反常目初始化英文标的两个重要办法
获取反常简略的描述信息:
String msg = exception.getMessage();
打印反常追踪的堆栈信息:
exception.printStackTrace();
实例
public class ExceptionTest08 {
public static void main(String[] args) {
// 这儿仅仅为了测验getMessage()办法和printStackTrace()办法。
// 这儿仅仅new了反常目标,可是没有将反常目标抛出。JVM会以为这是一个普通的java目标。
NullPointerException e = new NullPointerException("空指针反常fdsafdsafdsafds");
// 获取反常简略描述信息:这个信息实践上便是结构办法上面String参数。
String msg = e.getMessage(); //空指针反常fdsafdsafdsafds
System.out.println(msg);
// 打印反常堆栈信息
// java后台打印反常堆栈追踪信息的时分,选用了异步线程的办法打印的。
e.printStackTrace();
for(int i = 0; i < 1000; i++){
System.out.println("i = " + i);
}
System.out.println("Hello World!");
}
}
运行成果如下:
怎样检查反常并做处理
import java.io.FileInputStream;
import java.io.FileNotFoundException;
/*
咱们今后检查反常的追踪信息,咱们应该怎样看,能够快速的调试程序呢?
反常信息追踪信息,从上往下一行一行看。
可是需求留意的是:SUN写的代码就不用看了(看包名就知道是自己的仍是SUN的。)。
首要的问题是呈现在自己编写的代码上。
*/
public class ExceptionTest09 {
public static void main(String[] args) {
try {
m1();
} catch (FileNotFoundException e) {
// 获取反常的简略描述信息
String msg = e.getMessage();
System.out.println(msg); //C:jetns-agent.jar (体系找不到指定的文件。)
//打印反常堆栈追踪信息!!!
//在实践的开发中,主张运用这个。养成好习惯!
// 这行代码要写上,不然出问题你也不知道!
//e.printStackTrace();
/*
java.io.FileNotFoundException: C:jetns-agent.jar (体系找不到指定的文件。)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:155)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:110)
at com.bjpowernode.javase.exception.ExceptionTest09.m3(ExceptionTest09.java:31)
at com.bjpowernode.javase.exception.ExceptionTest09.m2(ExceptionTest09.java:27)
at com.bjpowernode.javase.exception.ExceptionTest09.m1(ExceptionTest09.java:23)
at com.bjpowernode.javase.exception.ExceptionTest09.main(ExceptionTest09.java:14)
由于31行出问题导致了27行
27行出问题导致23行
23行出问题导致14行。
应该先检查31行的代码。31行是代码过错的根源。
*/
}
// 这儿程序不耽误履行,很强健。《服务器不会由于遇到反常而宕机。》
System.out.println("Hello World!");
}
private static void m1() throws FileNotFoundException {
m2();
}
private static void m2() throws FileNotFoundException {
m3();
}
private static void m3() throws FileNotFoundException {
new FileInputStream("C:jetns-agent.jar");
}
}
Finally句子
"1、在finally子句中的代码是终究履行的,并且是必定会履行的,即便try句子块中的代码呈现了反常。
finally子句有必要和try一同呈现,不能独自编写。
"2、finally句子通常运用在哪些状况下呢?
通常在finally句子块中完结资源的释放/封闭。
由于finally中的代码比较有保证。
即便try句子块中的代码呈现反常,finally中代码也会正常履行。
实例
public class ExceptionTest10 {
public static void main(String[] args) {
FileInputStream fis = null; // 声明方位放到try外面。这样在finally中才能用。
try {
// 创立输入流目标
fis = new FileInputStream("D:course2-JavaSEdocumentJavaSE进阶讲义JavaSE进阶-01-面向目标.pdf");
// 开端读文件....
String s = null;
// 这儿必定会呈现空指针反常!
s.toString();
System.out.println("hello world!");
// 流运用完需求封闭,由于流是占用资源的。
// 即便以上程序呈现反常,流也有必要要封闭!
// 放在这儿有或许流关不了。
//fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch(IOException e){
e.printStackTrace();
} catch(NullPointerException e) {
e.printStackTrace();
} finally {
System.out.println("hello 浩克!");
// 流的封闭放在这儿比较稳妥。
// finally中的代码是必定会履行的。
// 即便try中呈现了反常!
if (fis != null) { // 防止空指针反常!
try {
// close()办法有反常,选用捕捉的办法。
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("hello kitty!");
}
}
Try和finally的连用
验证finally句子必定是终究履行的
public class ExceptionTest11 {
public static void main(String[] args) {
/*
try和finally,没有catch能够吗?能够。
try不能独自运用。
try finally能够联合运用。
以下代码的履行次序:
先履行try...
再履行finally...
终究履行 return (return句子只需履行办法必定完毕。)
*/
try {
System.out.println("try...");
return;
} finally {
// finally中的句子会履行。能履行到。
System.out.println("finally...");
}
// 这儿不能写句子,由于这个代码是无法履行到的。
//System.out.println("Hello World!");
}
}
关于Finally中的特例
"留意,当退出JVM的时分,Finally句子就不会履行了"
public class ExceptionTest12 {
public static void main(String[] args) {
try {
System.out.println("try...");
// 退出JVM
System.exit(0); // 退出JVM之后,finally句子中的代码就不履行了!
} finally {
System.out.println("finally...");
}
}
}
Finally易错点
"试推测下列result的返回值
public class Test {
public static void main(String[] args) {
int result = m();
System.out.println(result); //猜测成果
}
public static int m(){
int i = 100;
try {
return i;
} finally {
i++;
System.out.println("Finally中的i"+i);
}
}
}
分析
"java语法规矩(有一些规矩是不能破坏的,一旦这么说了,就有必要这么做!):
java中有一条这样的规矩:
办法体中的代码有必要遵循自上而下次序依次逐行履行(亘古不变的语法!)
java中还有一条语法规矩:
return句子一旦履行,整个办法有必要完毕(亘古不变的语法!)
运行成果
能够看出,虽然finally句子块履行了,可是,return的值仍是100!!
为什么?看看反编译的成果
public static int m(){
int i = 100;
int j = i;
i++;
return j;
}
"不难看出,在反编译的时分,引入了一个新的中心变量,来处理咱们的疑问
Final 、Finally、 Finalize的差异
"final 关键字
final润饰的类无法承继
final润饰的办法无法掩盖
final润饰的变量不能从头赋值。
"finally 关键字
和try一同联合运用。
finally句子块中的代码是有必要履行的。
"finalize 标识符
是一个Object类中的办法名。
这个办法是由废物收回器GC担任调用的。
实例
public class ExceptionTest14 {
public static void main(String[] args) {
// final是一个关键字。表示终究的。不变的。
final int i = 100;
//i = 200;
// finally也是一个关键字,和try联合运用,运用在反常处理机制中
// 在fianlly句子块中的代码是必定会履行的。
try {
} finally {
System.out.println("finally....");
}
// finalize()是Object类中的一个办法。作为办法名呈现。
// 所以finalize是标识符。
// finalize()办法是JVM的GC废物收回器担任调用。
Object obj;
}
}
// final润饰的类无法承继
final class A {
// 常量。
public static final double MATH_PI = 3.1415926;
}
class B {
// final润饰的办法无法掩盖
public final void doSome(){
}
}
自定义的生产异常处理反常类
Java中怎样自定义反常呢?
两步:
"榜首步:编写一个类承继Exception或许RuntimeException.
"第二步:供给两个结构办法,一个无参数的,一个带有String参数的。
实例
public class MyException extends Exception{ // 编译时反常
public MyException(){
}
public MyException(String s){
super(s);
}
}
反常的归纳实例
编写程序,运用一维数组,模仿栈数据结构。
要求:
1、这个栈能够存储java中的任何引证类型的数据。
2、在栈中供给push办法模仿压栈。(栈满了,要有提示信息。)
3、在栈中供给pop办法模仿弹栈。(栈空了,也有有提示信息。)
4、编写测验程序,new栈目标,调用push pop办法来模仿压栈弹栈的动作。
5、假设栈的默认初始化容量是10.(请留意无参数结构办法的编写办法。)
自定义反常办法
public class StackException extends Exception{
public StackException(){
}
public StackException(String s){
super(s);
}
}
测验类
import java.util.ArrayList;
import java.util.List;
public class Test {
static int temp = 0;
public static void main(String[] args) {
// 创立一个调集目标并指定其初始容量
List<Object> mylist = new ArrayList<Object>(10);//自定义栈的初始容量为10
// 创立一个本类的目标,便利来调用下面的实例办法
Test test = new Test();
// 模仿压栈
test.push(mylist,1);
test.push(mylist,2);
test.push(mylist,3);
test.push(mylist,4);
// 模仿弹栈
test.pop(mylist);
test.pop(mylist);
test.pop(mylist);
test.pop(mylist);
}
//压栈办法
public void push(List list,Object object){
if(temp <= 9){
list.add(temp,object);
System.out.println("添加元素"+object+"成功!");
temp++;
}else{
try {
throw new StackException("添加元素"+object+"失利,栈已满!!!");
} catch (StackException e) {
e.printStackTrace();
}
}
}
// 弹栈办法
public void pop (List list){
if(temp > 0){
Object o1 = list.get(temp-1);
list.remove(temp-1);
System.out.println("删去元素"+o1+"成功!!!");
temp--;
}else{
try {
throw new StackException("弹栈失利,栈已空!!!");
} catch (StackException e) {
e.printStackTrace();
}
}
}
}