Java Basics Part 19/20 - Exceptions

Java Basics Part 19/20 - Exceptions

目录


异常(Exception) 是运行期出现错误带来的问题。当程序发生异常的时候,会不正常终止,而这不是程序员想看到,所以就引入了 异常机制,来处理运行期抛出的异常。

异常可以由很多因素导致,下面是一些常见的异常场景:

  • 用户输入非法数据
  • 需要打开的文件不存在
  • 在通信过程中网络断开或者是 JVM 内存溢出了

一些异常由用户错误导致,还有一些有程序员导致,还有一些是物理资源导致。

基于上述原因种类不同,我们可以给异常分类:

  • Checked exceptions:checked exception 是在编译期间出现的异常,这些异常也叫作编译期异常。它们在编译期不能忽略,程序员应该把这些异常处理掉。
    比如,如果使用 FileReader 类读取一个文件,如果文件不存在,那么就会抛出 FileNotFoundException,编译期会提示程序员解决。

    import java.io.File;
    import java.io.FileReader;
    
    public class FilenotFound_Demo {
    
       public static void main(String args[]){      
          File file=new File("E://file.txt");
          FileReader fr = new FileReader(file); 
       }
    
    }
    
    // output
    FilenotFound_Demo.java:8: error: unreported exception     FileNotFoundException; must be caught or declared to be thrown
      FileReader fr = new FileReader(file);
  • Unchecked exceptions:Unchecked exceptions 是运行期会发生的异常,又叫做运行期异常,这些异常包括程序 bug,比如逻辑错误,API 的错误使用等等这些在编译器会忽略的异常。

    public class Unchecked_Demo {   
        public static void main(String args[]){
            int num[]={1,2,3,4};
            System.out.println(num[5]);
         }
    }
    // output
    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
    at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
  • Errors: 这些不是异常,而是一些程序员无法控制的问题。比如,栈溢出。


Exception Hierarchy

所有的 Exception 都是 java.lang.Exception 的子类。Exception 同时也是 Throwable 的子类。除了 Exception 之外,还有 Error 类也是 Throwable 的子类。

Exception 类有两个子类:IOException 和 RuntimeException。

Exception

这里有常见的 java 内置 Exception.


Exceptions Methods

下面列出了 Throwable 类的一些很重要的方法。

SN Methods with Description
1 public String getMessage():异常发生时返回的错误信息,这个信息在异常类构造器中初始化的。
2 public Throwable getCause():返回异常的原因
3 public String toString():返回类名+getMessage()
4 public void printStackTrace():打印 toString() 的结果,输出到 System.err
5 public StackTraceElement [] getStackTrace():返回调用栈元素的集合
6 public Throwable fillInStackTrace()

Catching Exceptions

可以使用 trycatch 来捕获异常。语法如下:

try {
   //Protected code
}catch(ExceptionName e1) {
   //Catch block
}

举例:

// File Name : ExcepTest.java
import java.io.*;
public class ExcepTest{

   public static void main(String args[]){
      try{
         int a[] = new int[2];
         System.out.println("Access element three :" + a[3]);
      }catch(ArrayIndexOutOfBoundsException e){
         System.out.println("Exception thrown  :" + e);
      }
      System.out.println("Out of the block");
   }
}

// output
Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block

Multiple catch Blocks

一个 try,后面可以接多个 catch:

try {
   //Protected code
}catch(ExceptionType1 e1) {
   //Catch block
}catch(ExceptionType2 e2) {
   //Catch block
}catch(ExceptionType3 e3) {
   //Catch block
}

举例:

try
{
   file = new FileInputStream(fileName);
   x = (byte) file.read();
}catch(IOException i)
{
   i.printStackTrace();
   return -1;
}catch(FileNotFoundException f) //Not valid!
{
   f.printStackTrace();
   return -1;
}

Catching multiple type of exceptions

从 Java 7 开始,一个 catch 语句块可以捕获多个异常。比如:

catch (IOException|FileNotFoundException ex) {
   logger.log(ex);
   throw ex;

The throws/throw Keywords

如果方法本身不会处理一个 checked exception,那么方法必须使用 throws 抛出这个异常。throws 关键字总是出现在方法签名的末尾。

方法中也可以使用 throw 关键字抛出一个异常。

throwsthrow 的区别:
throws 用来推迟 checked exception 的处理,throw 用来显示的触发一个异常。

下面这个例子,抛出了一个 RemoteException:

import java.io.*;
public class className
{
   public void deposit(double amount) throws RemoteException
   {
      // Method implementation
      throw new RemoteException();
   }
   //Remainder of class definition
}

方法也可以一次抛出多个异常。

import java.io.*;
public class className
{
   public void withdraw(double amount) throws RemoteException,
                              InsufficientFundsException
   {
       // Method implementation
   }
   //Remainder of class definition
}

The finally block

finally 块紧跟在 try…catch 后面。finally 块中的语句总是会执行,即使有异常发生。

通常使用 finally 语句块来做一些资源清理的工作。

语法如下:

try
{
   //Protected code
}catch(ExceptionType1 e1)
{
   //Catch block
}catch(ExceptionType2 e2)
{
   //Catch block
}catch(ExceptionType3 e3)
{
   //Catch block
}finally
{
   //The finally block always executes.
}

举例:

public class ExcepTest{

   public static void main(String args[]){
      int a[] = new int[2];
      try{
         System.out.println("Access element three :" + a[3]);
      }catch(ArrayIndexOutOfBoundsException e){
         System.out.println("Exception thrown  :" + e);
      }
      finally{
         a[0] = 6;
         System.out.println("First element value: " +a[0]);
         System.out.println("The finally statement is executed");
      }
   }
}

// output
Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
First element value: 6
The finally statement is executed

注意:

  • 无 try 不 catch
  • finally 不必在
  • 无 catch 或 finally 不 try
  • try catch finally 之间无代码

The try-with-resources

通常我们会使用一些资源(流,连接等等),使用完成后要关掉这些资源,如下所示,使用 FileReader,然后关闭它:

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class ReadData_Demo {

   public static void main(String args[]){
      FileReader fr=null;       
      try{
         File file=new File("file.txt");
         fr = new FileReader(file);  char [] a = new char[50];
         fr.read(a); // reads the content to the array
         for(char c : a)
         System.out.print(c); //prints the characters one by one
      }catch(IOException e){
          e.printStackTrace();
       }
       finally{ 
          try{
              fr.close();
          }catch(IOException ex){       
               ex.printStackTrace();
           }
       }
    }

}

代码比较多,使用 try-with-resources 句法后(Java 7 引进),try 中打开的资源会自动释放。
语法:

try(FileReader fr=new FileReader("file path")) {
   //use the resource
}catch(){
      //body of catch 
    }
}

举例:

import java.io.FileReader;
import java.io.IOException;

public class Try_withDemo {

   public static void main(String args[]){

      try(FileReader fr=new FileReader("E://file.txt")){
         char [] a = new char[50];
         fr.read(a); // reads the contentto the array
         for(char c : a)
         System.out.print(c); //prints the characters one by one
      }catch(IOException e){
          e.printStackTrace();
       }   
   }
}

下面这些要点要谨记:

  • 使用 try-with-resources 打开的类,必须实现 AutoCloseable接口,运行期会自动调用close()
  • 在 try-with-resources 中可用声明多个类
  • try 中声明的多个类会以相反的顺序关闭
  • 除了资源的声明之外,其他与 try/catch 无异
  • try 中声明的资源在 try 开始之前被初始化。
  • try 中声明的资源隐式的被修饰为 final 的

User-Define Exceptions

用户可以创建自己的异常类。自定义的时候注意以下几点:

  • 所有的异常都是 Throwable 的子类
  • 如果想写一个 checked exception,需要继承 Exception
  • 如果想写一个 runtime exception,需要继承 RuntimeException

举例:

// File Name InsufficientFundsException.java
import java.io.*;

public class InsufficientFundsException extends Exception
{
   private double amount;
   public InsufficientFundsException(double amount)
   {
      this.amount = amount;
   } 
   public double getAmount()
   {
      return amount;
   }
}

使用上述定义的异常:

// File Name CheckingAccount.java
import java.io.*;

public class CheckingAccount
{
   private double balance;
   private int number;

   public CheckingAccount(int number)
   {
      this.number = number;
   }

   public void deposit(double amount)
   {
      balance += amount;
   }

   public void withdraw(double amount) throws InsufficientFundsException
   {
      if(amount <= balance)
      {
         balance -= amount;
      }
      else
      {
         double needs = amount - balance;
         throw new InsufficientFundsException(needs);
      }
   }

   public double getBalance()
   {
      return balance;
   }

   public int getNumber()
   {
      return number;
   }
}

使用上述定义的类:

// File Name BankDemo.java
public class BankDemo
{
   public static void main(String [] args)
   {
      CheckingAccount c = new CheckingAccount(101);
      System.out.println("Depositing $500...");
      c.deposit(500.00);

      try
      {
         System.out.println("\nWithdrawing $100...");
         c.withdraw(100.00);
         System.out.println("\nWithdrawing $600...");
         c.withdraw(600.00);
      }catch(InsufficientFundsException e)
      {
         System.out.println("Sorry, but you are short $" + e.getAmount());
         e.printStackTrace();
      }
    }
}

// output
Depositing $500...

Withdrawing $100...

Withdrawing $600...
Sorry, but you are short $200.0
InsufficientFundsException
        at CheckingAccount.withdraw(CheckingAccount.java:25)
        at BankDemo.main(BankDemo.java:13)

Common Exceptions

Java 中,可以定义两种 Exceptions 和 Errors:

  • JVM Exceptions: 由 JVM 抛出的异常,例如:NullPointerException,ArrayIndexOutOfBoundsException,ClassCastException
  • Programmatic exceptions: 应用或者是API设计者抛出的异常,例如:IllegalArgumentException,IllegalStateException
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章