千家信息网

Java异常处理的技巧有哪些

发表于:2024-11-12 作者:千家信息网编辑
千家信息网最后更新 2024年11月12日,这篇文章将为大家详细讲解有关Java异常处理的技巧有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Java异常处理的9个技巧是:1. 仅在异常情况下使用异常2.
千家信息网最后更新 2024年11月12日Java异常处理的技巧有哪些

这篇文章将为大家详细讲解有关Java异常处理的技巧有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

Java异常处理的9个技巧是:

1. 仅在异常情况下使用异常2. 对可恢复条件使用检查异常,对编程错误使用运行时异常3. 避免不必要的使用受检异常4. 赞成使用标准异常5. 抛出适合抽象的异常6. 记录每个方法抛出的所有异常7. 在详细消息中包含故障捕获信息8. 力求故障原子性9. 不要忽视异常

1. 仅在异常情况下使用异常

此项主要是避免对普通控制流使用异常。

例如,不是使用异常来终止循环控制流:

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

应该使用对集合的常规迭代:

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

我没有找到任何使用常规控制流异常的示例。

2. 对可恢复条件使用检查异常,对编程错误使用运行时异常

大多数情况下,如果调用者可以恢复异常,则应使用已检查的异常。如果不是,则应使用运行时异常。运行时异常表示可以通过检查某些先决条件(例如数组边界和空性检查)来防止的编程错误。

在下面的方法中,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 parseTags(final String tagString) throws IllegalArgumentException {    // delimit by whitespace or '='    Scanner scanner = new Scanner(tagString).useDelimiter("\\s+|=");     Map tagMap = new HashMap();    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. 避免不必要的使用受检异常

检查异常强制调用者处理异常情况,因为如果没有,编译器会抱怨。过度使用检查异常会给调用者带来处理异常情况的负担。所以必要时应该使用受检异常。使用受检异常的经验法则是,当无法通过检查前提条件避免异常时,调用者可以采取一些有用的操作来处理异常。

常用的运行时异常本身就是不要过度使用检查异常的例子。在常见的运行时异常有:ArithmeticExceptionClassCastException异常,抛出:IllegalArgumentExceptionIllegalStateException异常,IndexOutOfBoundExceptionsNoSuchElementException异常,和NullPointerException异常。

在下面的方法中,当propertyName不是目标情况之一时,调用者可以做的事情不多,因此抛出运行时异常。

@Overridepublic 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.FileNotFoundException3.java.io.UnsupportedEncodingException4. java.lang.reflect.InvocationTargetException5.java.security.NoSuchAlgorithmException6.java.net.MalformedURLException7.java.text.ParseException8. java.net.URISyntaxException9. java.util.concurrent.ExecutionException10. java.net.UnknownHostException

前 10 名中没有一个是书中显示的最常用的。但是要注意,这些是按项目计算的,即如果一个类在一个项目中使用,无论项目中有多少方法在使用它,它都只计算一次。所以这是按项目数计算,但按代码中出现的次数计算。

5. 抛出适合抽象的异常

抛出的异常应该与调用者执行的任务有联系。此项介绍异常转换(捕获异常并抛出另一个)和异常链(将异常包装在新的异常中以保留异常的因果链)。

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("") + 13,                xml.indexOf("")).trim());        billingResult.setGrossAmount(billingDetails.getOverallCosts()                .getGrossAmount());        billingResult.setNetAmount(billingDetails.getOverallCosts()                .getNetAmount());    } catch (JAXBException | UnsupportedEncodingException ex) {        throw new BillingRunFailed(ex);    }}

上述方法捕获 JAXBExceptionUnsupportedEncodingException,并重新抛出一个适合方法抽象级别的新异常。新的 BillingRunFailed 异常包装了原始异常。所以这是异常链的一个很好的例子。异常链的好处是保留有助于调试问题的低级异常。

6. 记录每个方法抛出的所有异常

这是严重使用不足。大多数公共 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 项是关于失败的。一般规则是失败的方法不应该改变方法中对象的状态。为了尽早失败,一种方法是在执行操作之前检查参数的有效性。以下是遵循此提示的一个很好的示例。

/** * 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异常处理的技巧有哪些"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

0