Java 異常 隨機數 包裝類

ihav2carryon發表於2024-07-04

異常,隨機數,包裝類,日期類

正如 “人無完人”一樣,程式也不是完美的,它總會存在這樣那樣的問題,而有些問題並不是能夠透過程式設計師開發更好的程式碼來解決的,如果我們忽視它,可能就會造成程式的終止,甚至是系統的崩潰。因此,我們需要想辦法來合理的解決它,這就是Java中異常的由來。

異常

  • 異常的定義:是指在程式執行的過程中出現的非正常的情況,最終可能導致JVM的終止,異常本身是一個類,產生異常就是建立了異常物件並丟擲一個異常物件.
  • 誤區: 異常並不是語法錯誤,語法錯誤會直接導致程式無法編譯成功,不會產生.class檔案,而異常是在程式執行時發生的.

異常的分類

在java中,異常被當成一個物件來看待,其根類是java.lang.Throwable ,Throwable類又分為ErrorException

  1. Error:不能處理的異常,這是系統內部異常,執行時報錯,屬於系統問題.一般發生Error異常,JVM會選擇終止程式,開發人員需提前避免該異常
  2. Exception:可以處理的異常,這是比較常見的異常,開發人員可以根據java中異常得類來處理.

Error

  • 對於嚴重的Error,沒有辦法處理,只能做到提起規避.常見的Error有:(棧溢位錯誤)和(記憶體溢位錯誤)。
  • Java中堆是用來儲存物件例項的,因此如果我們不斷地建立物件, 並且物件沒有被垃圾回收, 那麼當建立的物件過多時, 會導致記憶體不足, 進而引發 異常。

Exception

我們一般說的異常都是指的是Exception異常,這種異常一旦出現我們就要堆程式碼進行更正修復程式.

  • 根據編譯時期還是執行時期可以將異常分為一下兩類

編譯時異常(checked Exception)

  • 即在編譯時期就會檢查程式是否有的異常,如何沒有處理異常,則會編譯失敗,如檔案無法找到等異常,異常對於編譯時異常我們必須處理否則無法編譯透過.

執行時異常(runtime Exception)

  • 即在執行時就對程式檢查的異常,在編譯時期執行異常不會被編譯器檢測(開發工具不會提示,只有執行時才會報的異常),如空指標異常,型別轉化異常,數字操作異常.
public class Test01 {
    public static void main(String[] args)  {
        //FileInputStream inputStream = new FileInputStream("java筆記.txt");//會報編譯時異常
        String str=null;
        System.out.println(str.length());//執行時異常->空指標異常
        Object o = new Object();
        String s=(String) o;//執行時異常->型別轉換異常
        int i=10/0;//執行時異常->數字操作異常
    }
}

異常的傳遞

在java程式try 語塊中丟擲一個異常,若這個異常沒有被catch語句塊捕獲,這個異常會沿著呼叫棧向上傳遞,直到它被某個catch 語句捕獲,或者若直到到達程式頂層(main方法或程式入口)仍沒有被捕獲,那麼程式就會終止,並列印出異常堆疊的資訊.該過程就是異常傳遞

異常的處理

異常的處理有三種,throw(丟擲),throws(宣告,向上拋),try-catch(捕獲)程式碼塊

throw

java程式出現異常時會建立一個異常物件,該物件將會被提交到java執行系統,並將控制權轉移給能夠處理該異常的程式碼,這個過程被稱為丟擲→丟擲一個異常物件

  • 自動生成:程式執行時,JVM檢測到程式發生了問題,如果在當前程式碼中沒有找到相應的處理程式,就會在後臺自動建立一個對應的異常類的例項物件並丟擲,即自動丟擲
  • 手動生成: Expectation expectaion=new Expectation(); 這樣建立的異常物件若不丟擲則對程式沒有任何影響,即和建立一個普通物件一樣,但是一旦丟擲,就會對程式執行產生影響,會導致程式終止.
//自動丟擲異常例子
public class Test01 {
    public static void main(String[] args)  {
      int arr[]={1,2,3,4};
      int index=4;
      //我們寫相應的異常處理程式程式碼,由虛擬機器自動檢測建立異常物件自動丟擲。
        System.out.println(getElements(arr, index));
    }
    public  static int getElements(int arr[],int index)
    {
        return arr[index];//下標越界之後JVM會自動識別異常並建立一個異常物件並丟擲
    }
}
//手動丟擲異常
public class Test01 {
    public static void main(String[] args)  {
      int arr[]={1,2,3,4};
      int index=4;
        System.out.println(getElements(arr, index));
    }
    public  static int getElements(int arr[],int index)
    {
        if (arr==null) throw new NullPointerException("陣列為空");//手動丟擲異常
        if(index<0||index>arr.length-1) throw new IndexOutOfBoundsException("下標越界");
        return arr[index];
    }
}

throws

throw 不同相同的是,throws,只是在可能出現異常的方法宣告異常,throws不會丟擲一個異常物件,作用的物件是方法

  • 不處理異常:try-catch 不同,throws 並不會在方法內部處理異常,只是宣告告訴呼叫者”該方法可能會丟擲這些異常,你需要處理它”若呼叫者不處理可接著throws 接著甩鍋
  • 向上傳遞:若一個地方使用了throws 宣告瞭可能會丟擲的異常,但方法內部沒有將其捕獲,那麼這些異常會向上傳遞到呼叫該方法的程式碼中.
  • 受檢查異常與非受檢查異常:
public class Test01 {
    public static void main(String[] args) //在主函式也可以向上丟擲FileNotFoundException
    {
    //呼叫該方法時會報錯,以為getFile的異常被拋到呼叫其方法的程式碼
      getFile();
    }
    public  static void getFile () throws FileNotFoundException//向上丟擲異常,但不處理,交給呼叫者處理
    {
        FileInputStream inputStream = new FileInputStream("java開發");
    }
}

try-catch

try-catch 的核心思想是將程式中可能會出現異常的程式碼塊(try塊)與處理異常程式碼(catch塊)分離,從而提高程式處理異常的能力

  • 異常捕獲:try 塊中包含了可能丟擲異常的程式碼.當執行這些程式碼發生異常,java會立即停止try塊中的剩餘程式碼,建立一個異常物件並丟擲,並查詢與之匹配的catch塊.
  • 異常處理:catch 用於處理try塊中
public class Test02 {
    public static void main(String[] args) {
        int result;
        try{
            result=10/0; //此時有除0異常
            System.out.println("result:" + result);//若沒有異常此語句將會被執行
        }
        catch (ArithmeticException e){
            System.err.println("An arithmeticException happened here"+e.getMessage());
        }
        System.out.println("try-catch語句之後保持順序執行");
    }
}

finally

finally是java異常處理中一個重要的部分,它與try語句和catch語句共同使用,以確保無論是否發生異常,某些程式碼都是能執行的 ,即finally塊用於包含那些無論是否發生異常都必須執行的程式碼

執行時機

  • 正常完成:如果try 塊中的程式碼正常執行,沒有發生異常,則finally塊在try塊之後執行
  • 異常發生:如果try塊中的的程式碼丟擲異常,並且這個異常被相應的catch塊捕獲(或者沒有被catch捕獲但異常被傳遞出去),則finally塊會在catch塊之後執行,或者是在try塊之後異常傳遞之前執行
  • Return:若在try塊和catch塊中帶有return關鍵字,則finally塊會在return之前執行,但finally塊不會改變return的返回值,除非finally塊中也包含return語句,則返回finally塊中的值
public class Test01 {
    public static void main(String[] args)throws 
    {
    getFile();
    }
    public  static void getFile () 
    {
        try {
            //可能會找不到檔案
            FileInputStream inputStream = new FileInputStream("java開發");
        }
        catch (FileNotFoundException e){
            //若找不到檔案者丟擲notFound異常
            System.out.println(e.getMessage());
        }
        finally { 
            //無論如何都會執行關閉檔案語句
            System.out.println("關閉檔案");
        }
    }
}

自定義異常

透過繼承java中Exception類或其他子類(如RuntimeException)來建立異常類,該方式可以讓開發者自定義特定的錯誤異常,可以更靈活和準確處理程式中的錯誤異常

自定義異常的建立

  1. 確定基類(父類)
  • 自定義異常應該繼承相應的Exception或其子類,如希望檢驗受檢異常則應該繼承Exception,如果希望執行時異常,則應該繼承RuntimeException 因此在每次自定義異常時要準確的繼承相應基類
  1. 編寫自定義異常類
  • 可以建立一個新的類,並使其繼承所選擇的異常父類
  • 可新增自定義屬性和方法
  • 可重寫相應的的toString() getMessage()方法
public class LessThan0Exception extends RuntimeException{
//自定義一個異常類LessThan0Exception 繼承了RuntimeException類
    public LessThan0Exception() { //無參構造方法
        super("該數為負數!");//呼叫父類丟擲資訊方法
    }
}
 public static void main(String[] args) {
        int age=-10;//主函式中
        if(age<10)
        {  //若age為負數則會丟擲自定義異常
            throw new LessThan0Exception();
        }
    }

隨機數

隨機數在日常開發中也是十分常見的,例如抽獎,隨機點名等等,所有隨機數都是Random類的使用

基本用法

 public static void main(String[] args) {
        Random random = new Random();//例項化一個random物件
        System.out.println(random.nextInt());//隨機產生一個int型別的數
        System.out.println(random.nextInt(10));//隨機產生一個[0,10)的數
        System.out.println(random.nextDouble());//隨機產生一個雙精度的浮點數
        System.out.println(random.nextDouble(10));//隨機產生一個[0,9)的浮點數
    }

日期類

在開發工作中日期類也是十分常見的

Date

作為一個最基礎的日期類,是我們學習的必要

  public static void main(String[] args) {
        Date date = new Date();
        //Date重寫了toString()方法
        System.out.println(date);//以美國國家習慣列印出該天的日期格式符
        System.out.println(date.getTime());//列印從1970.01.01到目前為止的毫秒數
    }

日曆類

 public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();//獲取日曆類物件

        System.out.println(calendar.get(Calendar.YEAR));//獲取當前年份
        System.out.println((calendar.get(Calendar.MONTH) + 1));//獲取當前月份
        //由於java月份範圍是[0,11] 因此要加上一個1
        System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//顯示今天是該月的第幾天
        System.out.println(calendar.get(Calendar.HOUR));//獲取當前小時數(12進位制)
        System.out.println(calendar.get(Calendar.HOUR_OF_DAY));//獲取當前小時(24進位制)
        System.out.println(calendar.get(Calendar.MINUTE));//獲取分鐘數
        System.out.println(calendar.get(Calendar.SECOND));//獲取秒數
        System.out.println(calendar.get(Calendar.MILLISECOND));//獲取毫秒數
        System.out.println(calendar.get(Calendar.DAY_OF_YEAR));//獲取該填是該年的第幾天
        System.out.println(calendar.get(Calendar.DAY_OF_WEEK));//獲取該天是該周的第幾天即 星期幾
        calendar.set(Calendar.MONTH,6);//設定當前月份為6月
        System.out.println(calendar.get(Calendar.MONTH));
        calendar.add(Calendar.YEAR,1);//add(),將y,m,d或加上一定的數
        System.out.println(calendar.get(Calendar.YEAR));
        calendar.getTime();
    }

SimpleDataFormat

該類是用於格式化和解析日期的具體類,允許進行格式化(日期→文字),解析(文字→日期)和規範化

  • 構造方法:SimpleDataFormat(String pattern) 指定日期格式 其中y:年,MM:月,dd日 HH:小時,mm:分鐘,ss秒;例如”yyyy-MM-dd HH:mm:ss” 則表示為 2024-07-03 22:42:15
  • 日期格式化:

 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //將當前的日期格式化為yyyy-MM-dd HH:mm:ss
        String date=simpleDateFormat.format(new Date());//傳入一個Date型別的引數
        System.out.println(date);
        結果為:2024-07-03 23:26:58
  • 日期解析:在日期解析中會用到SimpleDateFormat類中的Parse函式,其主要的作用是資料型別的轉換(包括將字串轉化為程式所需的型別,int,float,date,time等等),複雜資料結構的生成(主要包括引用資料型別,陣列,列表,等等),
String dateString="2000-01-01 12:00:00";
       try{   //可能會出現解析錯誤異常因此要做好異常處理
           Date date1 = simpleDateFormat.parse(dateString);
           System.out.println(date1);
       }
       catch (ParseException e)
       {  //當出現解析錯誤異常則向控制檯列印出相應的錯誤
          e.printStackTrace();
       }
       結果為:Sat Jan 01 12:00:00 CST 2000

包裝類

包裝類,是基本資料型別的封裝形式,它允許將基本資料型別當作物件來處理,從而可以呼叫相應的方法.

基本資料型別與包裝類對應關係

基本資料型別 包裝類
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

包裝類的作用

  • 提供物件化的方法:包裝類提供了一系列的方法,允許對基本資料型別進行跟複雜的操作,如型別轉化,解析字串等等
  • 自動裝箱與拆箱:允許包裝類與基本資料型別可以相互轉化,簡化了程式設計工作

自動裝箱與拆箱

自動裝箱

自動裝箱指的是java編譯器在編譯階段自動將基本資料型別轉化為包裝類,該過程是透明的,無需手動編寫程式碼

         int num=10;
        Integer integer = num; //相當於Integer integer= Integer.valueof(num);
        System.out.println(integer);

解釋:num是基本資料型別int,integer是一個Integer型別變數,當把num的值賦給integer時,編譯器會自動執行裝箱操作,將int型別的num轉化為Integer型別

底層實現原理

  • 自動裝箱實際是呼叫包裝類valueOf() 方法實現的,編譯器會自動將裝箱操作轉化為對valueOf()方法的呼叫,例如上述例子就是自動呼叫了
Integer integer=Integer.valueOf(num);
  • 注意!!

每次JVM執行時,對於Integer,Short,Byte,Character,Boolean 會自動快取-128到127之間的整數(Byte,Short)以及字元值和布林值.這意味著在給範圍內的裝箱操作會返回快取中的物件引用,而不是新建立物件

自動拆箱

自動拆箱是裝箱的逆過程,指的是在編譯階段自動將包裝類轉化為基本資料型別的過程,該操作也是透明的,無需手寫轉化程式碼

  Integer integer=10;
      int i=integer;// int num=integer.intValue(i);
        System.out.println(i);

解釋:num是基本資料型別int,integer是一個Integer型別變數,當把num的值賦給integer時,編譯器會自動執行拆箱操作,將Integer型別的num轉化為int型別

底層實現原理

自動拆箱的過程實際上是呼叫了包裝類中的xxxValue()方法(如 doubleValue(),intValue()),編譯器會自動將拆箱操作轉化為相對應的xxxValue() 操作,上述例子實際被編譯器轉為

相關文章