java異常之運行期異常和checked異常

運行期異常和checked異常的區別:

Throwable 是全部 Java 程序中錯誤處理的父類 ,有兩種資類: Error 和 Exception 。java

Error :表示由 JVM 所偵測到的沒法預期的錯誤,因爲這是屬於 JVM 層次的嚴重錯誤 ,致使 JVM 沒法繼續執行,所以,這是不可捕捉到的,沒法採起任何恢復的操做,頂多只能顯示錯誤信息。spring

Exception :表示可恢復的例外,這是可捕捉到的。 Java 提供了兩類主要的異常 :runtime exception 和 checked exception 。編程

checked 異常也就是咱們常常遇到的 IO 異常,以及 SQL 異常都是這種異常。 對於這種異常, JAVA 編譯器強制要求咱們必需對出現的這些異常進行 catch 。因此,面對這種異常無論咱們是否願意,只能本身去寫一大堆 catch 塊去處理可能的異常。網絡

可是另一種異常: runtime exception ,也稱運行時異常,咱們能夠不處理。當出現這樣的異常時,老是由虛擬機 接管。好比:咱們歷來沒有人去處理過 NullPointerException 異常,它就是運行時異常,而且這種異常仍是最多見的異常之一。 出現運行時異常後,系統會把異常一直往上層拋,一直遇處處理代碼。若是沒有處理塊,到最上層,若是是多線程就由 Thread.run() 拋出 ,若是是單線程就被 main() 拋出 。拋出以後,若是是線程,這個線程也就退出了。若是是主程序拋出的異常,那麼這整個程序也就退出了。運行時異常是 Exception 的子類,也有通常異常的特色,是能夠被 Catch 塊處理的。只不過每每咱們不對他處理罷了。也就是說,你若是不對運行時異常進行處理,那麼出現運行時異常以後,要麼是線程停止,要麼是主程序終止。 若是不想終止,則必須撲捉全部的運行時異常,決不讓這個處理線程退出。隊列裏面出現異常數據了,正常的處理應該是把異常數據捨棄,而後記錄日誌。不該該因爲異常數據而影響下面對正常數據的處理。 在這個場景這樣處理多是一個比較好的應用,但並不表明在全部的場景你都應該如此。若是在其它場景,遇到了一些錯誤,若是退出程序比較好,這時你就能夠不太理會運行時異常 ,或者是經過對異常的處理顯式的控制程序退出。 異常處理的目標之一就是爲了把程序從異常中恢復出來 。多線程

擴展——關於spring事務回滾:

在service層的函數添加了spring掃描和事務註解之後,當函數執行跑出運行期異常spring會自動回滾事務。ide

因此自定義的業務異常必需要繼承RuntimeException。函數

並且運行期異常不能被catch否則,事務不會回滾。spa

public void method2(){
		//方法定義中不拋出運行期異常也能夠編譯經過
		throw new RuntimeException();
	}

執行結果:線程

Exception in thread "main" java.lang.RuntimeException
	at test.temp.RuntimeExcetionMethods.method2(RuntimeExcetionMethods.java:11)
	at test.temp.RuntimeExcetionMethods.main(RuntimeExcetionMethods.java:23)

在service中處理異常參考下面的方法:日誌

/**
	 * 執行秒殺操做
	 * 
	 * @param seckillId 秒殺商品ID
	 * @param userPhone 秒殺用戶電話
	 * @param md5 
	 * @return
	 * @throws SeckillCloseException
	 *             秒殺關閉異常
	 * @throws RepeatKillException
	 *             重複秒殺異常
	 * @throws SeckillException
	 *             秒殺異常
	 */
	@Override
	@Transactional
	/**
	 * 使用註解控制事務的優勢: 1:開發團隊達成一致約定,明確標註事務方法的編程風格
	 * 2:保證事務方法的執行時間儘量短,不要穿插其餘的網絡操做,RPC/HTTP請求,或者剝離到事務方法外.
	 * 3:不是全部的方法都須要事務,如:只有一條修改操做,只讀操做不須要事務控制。
	 */
	public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
			throws SeckillCloseException, RepeatKillException, SeckillException {
		if (md5 != null && md5.equals(getMD5(seckillId))) {
			try {
				// 秒殺邏輯:減庫存+記錄秒殺行爲
				// 減庫存
				int updateCount_seckill = seckillDao.reduceNumber(seckillId, new Date());
				if (updateCount_seckill <= 0) {
					// 沒有更新數據,秒殺未開啓或沒有庫存
					throw new SeckillCloseException("秒殺未開啓");
				}
				// 記錄秒殺行爲
				int updateCount_successKilled = successKilledDao.insertSuccessKilled(seckillId, userPhone);
				if (updateCount_successKilled <= 0) {
					// 沒有更新數據,重複秒殺
					throw new RepeatKillException("重複秒殺");
				}
				SuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(seckillId, userPhone);
				return new SeckillExecution(seckillId, SeckillStateEnum.SUCCESS, successKilled);
			} catch (SeckillCloseException e) {// 爲了不都被捕捉到Exception裏,爲了使spring捕捉並數據回滾以及在controller中處理對應的異常,因此須要在這裏分別捕捉再拋出對應異常。
				throw e;
			} catch (RepeatKillException e) {
				throw e;
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
				// 全部編譯期異常,轉化爲運行期異常
				throw new SeckillException("秒殺內部異常:" + e.getMessage());
			}

		} else {
			throw new SeckillException("秒殺數據篡改");
		}

	}
相關文章
相關標籤/搜索