溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java異常處理的技巧有哪些

發(fā)布時間:2022-02-28 11:03:01 來源:億速云 閱讀:146 作者:小新 欄目:開發(fā)技術

這篇文章將為大家詳細講解有關Java異常處理的技巧有哪些,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

Java異常處理的9個技巧是:

1. 僅在異常情況下使用異常
2. 對可恢復條件使用檢查異常,對編程錯誤使用運行時異常
3. 避免不必要的使用受檢異常
4. 贊成使用標準異常
5. 拋出適合抽象的異常
6. 記錄每個方法拋出的所有異常
7. 在詳細消息中包含故障捕獲信息
8. 力求故障原子性
9. 不要忽視異常

1. 僅在異常情況下使用異常

此項主要是避免對普通控制流使用異常。

例如,不是使用異常來終止循環(huán)控制流:

try{
  Iterator<Foo> iter = ...;
  while(true) {
    Foo foo = i.next();
    ...
  }
} catch (NoSuchElementException e){
}

應該使用對集合的常規(guī)迭代:

for(Iterator<Foo> iter = ...; i.hasNext();){
  Foo foo = i.next();
  ...
}

我沒有找到任何使用常規(guī)控制流異常的示例。

2. 對可恢復條件使用檢查異常,對編程錯誤使用運行時異常

大多數(shù)情況下,如果調用者可以恢復異常,則應使用已檢查的異常。如果不是,則應使用運行時異常。運行時異常表示可以通過檢查某些先決條件(例如數(shù)組邊界和空性檢查)來防止的編程錯誤。

在下面的方法中,IllegalArgumentException 是一個 RuntimeException,它的用法表示編程錯誤。通??梢酝ㄟ^檢查前提條件來避免編程錯誤。所以這是基于這個技巧的一個不好的例子。可以通過檢查先決條件來避免異常,即這里的“hasNext()”方法。

/**
 * Convert a tag string into a tag map.
 *
 * @param tagString a space-delimited string of key-value pairs. For example, {@code "key1=value1 key_n=value_n"}
 * @return a tag {@link Map}
 * @throws IllegalArgumentException if the tag string is corrupted.
 */
public static Map<String, String> parseTags(final String tagString) throws IllegalArgumentException {
    // delimit by whitespace or '='
    Scanner scanner = new Scanner(tagString).useDelimiter("\\s+|=");
 
    Map<String, String> tagMap = new HashMap<String, String>();
    try {
        while (scanner.hasNext()) {
            String tagName = scanner.next();
            String tagValue = scanner.next();
            tagMap.put(tagName, tagValue);
        }
    } catch (NoSuchElementException e) {
        // The tag string is corrupted.
        throw new IllegalArgumentException("Invalid tag string '" + tagString + "'");
    } finally {
        scanner.close();
    }
 
    return tagMap;
}

3. 避免不必要的使用受檢異常

檢查異常強制調用者處理異常情況,因為如果沒有,編譯器會抱怨。過度使用檢查異常會給調用者帶來處理異常情況的負擔。所以必要時應該使用受檢異常。使用受檢異常的經驗法則是,當無法通過檢查前提條件避免異常時,調用者可以采取一些有用的操作來處理異常。

常用的運行時異常本身就是不要過度使用檢查異常的例子。在常見的運行時異常有:ArithmeticException,ClassCastException異常,拋出:IllegalArgumentExceptionIllegalStateException異常,IndexOutOfBoundExceptions,NoSuchElementException異常,和NullPointerException異常。

在下面的方法中,當propertyName不是目標情況之一時,調用者可以做的事情不多,因此拋出運行時異常。

@Override
public Object get(String propertyName) {
  switch (propertyName.hashCode()) {
    case 842855857:  // marketDataName
      return marketDataName;
    case -1169106440:  // parameterMetadata
      return parameterMetadata;
    case 106006350:  // order
      return order;
    case 575402001:  // currency
      return currency;
    case 564403871:  // sensitivity
      return sensitivity;
    default:
      throw new NoSuchElementException("Unknown property: " + propertyName);
  }
}

4. 贊成使用標準異常

最常重用的 Java 異常類如下:

1.java.io.IO異常
2.java.io.FileNotFoundException
3.java.io.UnsupportedEncodingException
4. java.lang.reflect.InvocationTargetException
5.java.security.NoSuchAlgorithmException
6.java.net.MalformedURLException
7.java.text.ParseException
8. java.net.URISyntaxException
9. java.util.concurrent.ExecutionException
10. java.net.UnknownHostException

前 10 名中沒有一個是書中顯示的最常用的。但是要注意,這些是按項目計算的,即如果一個類在一個項目中使用,無論項目中有多少方法在使用它,它都只計算一次。所以這是按項目數(shù)計算,但按代碼中出現(xiàn)的次數(shù)計算。

5. 拋出適合抽象的異常

拋出的異常應該與調用者執(zhí)行的任務有聯(lián)系。此項介紹異常轉換(捕獲異常并拋出另一個)和異常鏈(將異常包裝在新的異常中以保留異常的因果鏈)。

private void serializeBillingDetails(BillingResult billingResult,
        BillingDetailsType billingDetails) {
 
    try {
        final JAXBContext context = JAXBContext
                .newInstance(BillingdataType.class);
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        final Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty("jaxb.formatted.output", Boolean.FALSE);
        final BillingdataType billingdataType = new BillingdataType();
        billingdataType.getBillingDetails().add(billingDetails);
        marshaller.marshal(factory.createBillingdata(billingdataType), out);
        final String xml = new String(out.toByteArray(), "UTF-8");
        billingResult.setResultXML(xml.substring(
                xml.indexOf("<Billingdata>") + 13,
                xml.indexOf("</Billingdata>")).trim());
        billingResult.setGrossAmount(billingDetails.getOverallCosts()
                .getGrossAmount());
        billingResult.setNetAmount(billingDetails.getOverallCosts()
                .getNetAmount());
    } catch (JAXBException | UnsupportedEncodingException ex) {
        throw new BillingRunFailed(ex);
    }
}

上述方法捕獲 JAXBException UnsupportedEncodingException,并重新拋出一個適合方法抽象級別的新異常。新的 BillingRunFailed 異常包裝了原始異常。所以這是異常鏈的一個很好的例子。異常鏈的好處是保留有助于調試問題的低級異常。

6. 記錄每個方法拋出的所有異常

這是嚴重使用不足。大多數(shù)公共 API 都沒有 @throws Java 文檔來解釋拋出的異常。

這是一個很好的例子。

...
 *
 * @throws MalformedURLException The formal system identifier of a
 * subordinate catalog cannot be turned into a valid URL.
 * @throws IOException Error reading subordinate catalog file.
 */
public String resolveSystem(String systemId)
  throws MalformedURLException, IOException {
...

這是一個缺乏有關在什么情況下拋出異常的信息的壞例子。

 * @throws Exception exception
 */
public void startServer() throws Exception {
    if (!externalDatabaseHost) {

7. 在詳細消息中包含故障捕獲信息

private OutputStream openOutputStream(File file) throws IOException {
    if (file.exists()) {
        if (file.isDirectory()) {
            throw new IOException("File '" + file + "' exists but is a directory");
        }
        if (!file.canWrite()) {
            throw new IOException("File '" + file + "' cannot be written to");
        }
    } else {
        final File parent = file.getParentFile();
        if (parent != null) {
            if (!parent.mkdirs() && !parent.isDirectory()) {
                throw new IOException("Directory '" + parent + "' could not be created");
            }
        }
    }
    return new FileOutputStream(file, false);
}

在該方法中,IOException 使用不同的字符串來傳遞不同的故障捕獲信息。

8.力求故障原子性

第 8 項是關于失敗的。一般規(guī)則是失敗的方法不應該改變方法中對象的狀態(tài)。為了盡早失敗,一種方法是在執(zhí)行操作之前檢查參數(shù)的有效性。以下是遵循此提示的一個很好的示例。

/**
 * Assigns a new int value to location index of the buffer instance.
 * @param index int
 * @param newValue int
 */
public void modifyEntry(int index, int newValue) {
        if (index < 0 || index > size - 1) {
            throw new IndexOutOfBoundsException();
        }
 
//        ((int[]) bufferArrayList.get((int) (index / pageSize)))[index % pageSize] =
        ((int[]) bufferArrayList.get((index >> exp)))[index & r] =
            newValue;
}

9. 不要忽視異常

public static Bundle decodeUrl(String s) {
    Bundle params = new Bundle();
    if (s != null) {
        String array[] = s.split("&");
        for (String parameter : array) {
            String v[] = parameter.split("=");
            try {
                params.putString(URLDecoder.decode(v[0], "UTF-8"), URLDecoder.decode(v[1], "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
    }
    return params;
}

在生產代碼中幾乎總是應該避免打印堆棧跟蹤。這與忽略異常一樣糟糕。這將寫入標準錯誤流,這不是日志使用日志記錄框架的地方。

關于“Java異常處理的技巧有哪些”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI