java中的异常--Exceptions in Java-- 第三部分

简介: Must enter integer as first argument. Although the above example had only one catch clause, you can have many catch clauses associated with a single try block.
Must enter integer as first argument.

Although the above example had only one catch clause, you can have many catch clauses associated with a single try block. Here's an example:

  // In Source Packet in file except/ex1/VirtualCafe.java
class VirtualCafe {
    public static void serveCustomer(VirtualPerson cust,
        CoffeeCup cup) {
        try {
            cust.drinkCoffee(cup);
            System.out.println("Coffee is just right.");
        }
        catch (TooColdException e) {
            System.out.println("Coffee is too cold.");
            // Deal with an irate customer...
        }
        catch (TooHotException e) {
            System.out.println("Coffee is too hot.");
            // Deal with an irate customer...
        }
    }
}

                    


If any code inside a try block throws an exception, its catch clauses are examined in their order of appearance in the source file. For example, if the try block in the above example throws an exception, the catch clause for TooColdException will be examined first, then the catch clause for TooHotException. During this examination process, the first catch clause encountered that handles the thrown object's class gets to "catch" the exception. The ordering of catch-clause examination matters because it is possible that multiple catch clauses of a try block could handle the same exception.

catch clauses indicate the type of abnormal condition they handle by the type of exception reference they declare. In the example above, the catch clauses declare exception type TooColdException and TooHotException. Had a single catch clause declared a TemperatureException, a thrown TooColdException or TooHotException still would have been caught, because TemperatureException is the superclass of both these classes. In the object-oriented way of thinking, a TooColdException is a TemperatureException, therefore, a catch clause for TemperatureException also will catch a thrown TooColdException. An example of this is shown below:

                        // In Source Packet in file except/ex2/VirtualCafe.java
class VirtualCafe {
    public static void serveCustomer(VirtualPerson cust,
        CoffeeCup cup) {
        try {
            cust.drinkCoffee(cup);
            System.out.println("Coffee is just right.");
        }
        catch (TemperatureException e) {
            // This catches TooColdException, TooHotException,
            // as well as TemperatureException.
            System.out.println("Coffee is too cold or too hot.");
            // Deal with an irate customer...
        }
    }
}

                    


Multiple catch clauses could handle the same exception because you may, for example, declare two catch clauses, one for TooColdException and another for TemperatureException. In this case, however, you must place the catch clause for TooColdException above the one for TemperatureException, or the source file won't compile. If a catch clause for TemperatureException could be declared before a catch clause for TooColdException, the first catch clause would catch all TooColdExceptions, leaving nothing for the second catch clause to do. The second catch clause would never be reached. The general rule is: subclass catch clauses must precede superclass catch clauses. Here's an example of both orders, only one of which compiles:

                        // In Source Packet in file except/ex3/VirtualCafe.java
class VirtualCafe {
    public static void serveCustomer(VirtualPerson cust,
        CoffeeCup cup) {
        try {
            cust.drinkCoffee(cup);
            System.out.println("Coffee is just right.");
        }
        catch (TemperatureException e) {
            // This catches TooColdException, TooHotException,
            // as well as TemperatureException.
            System.out.println("Coffee is too cold or too hot.");
            // Deal with an irate customer...
        }
        // THIS WON'T COMPILE, BECAUSE THIS catch clause
        // WILL NEVER BE REACHED.
        catch (TooColdException e) {
            System.out.println("Coffee is too cold.");
        }
    }
}
// In Source Packet in file except/ex4/VirtualCafe.java
// This class compiles fine.
class VirtualCafe {
    public static void serveCustomer(VirtualPerson cust,
        CoffeeCup cup) {
        try {
            cust.drinkCoffee(cup);
            System.out.println("Coffee is just right.");
        }
        catch (TooColdException e) {
            System.out.println("Coffee is too cold.");
            // Deal with an irate customer...
        }
        catch (TemperatureException e) {
            // This catches TooHotException as well
            // as TemperatureException.
            System.out.println(
                "There's temperature trouble in this coffee.");
            // Deal with an irate customer...
        }
    }
}

                    


Embedding information in an exception object
When you throw an exception, you are performing a kind of structured go-to from the place in your program where an abnormal condition was detected to a place where it can be handled. The Java virtual machine uses the class of the exception object you throw to decide which catch clause, if any, should be allowed to handle the exception. But an exception doesn't just transfer control from one part of your program to another, it also transmits information. Because the exception is a full-fledged object that you can define yourself, you can embed information about the abnormal condition in the object before you throw it. The catch clause can then get the information by querying the exception object directly.

The Exception class allows you to specify a String detail message that can be retrieved by invoking getMessage() on the exception object. When you define an exception class of your own, you can give client programmers the option of specifying a detail message like this:

                        // In Source Packet in file except/ex5/UnusualTasteException.java
class UnusualTasteException extends Exception {
    UnusualTasteException() {
    }
    UnusualTasteException(String msg) {
        super(msg);
    }
}

                    


Given the above declaration of UnusualTasteException, client programmers could create an instance in one of two ways:

new UnusualTasteException()
new UnusualTasteException("This coffee tastes like tea.")

 

A catch clause can then query the object for a detail string, like this:

                        // In Source Packet in file except/ex5/VirtualCafe.java
class VirtualCafe {
    public static void serveCustomer(VirtualPerson cust,
        CoffeeCup cup) {
        try {
            cust.drinkCoffee(cup);
            System.out.println("Coffee tastes just right.");
        }
        catch (UnusualTasteException e) {
            System.out.println(
                "Customer is complaining of an unusual taste.");
            String s = e.getMessage();
            if (s != null) {
                System.out.println(s);
            }
            // Deal with an unhappy customer...
        }
    }
}

                    


When you need to embed more information into an exception object than you can represent with a String, you can add data and access methods to your exception class. For example, you could define the temperature exception classes like this:

                        // In Source Packet in file except/ex6/TemperatureException.java
abstract class TemperatureException extends Exception {
    private int temperature; // in Celsius
    public TemperatureException(int temperature) {
        this.temperature = temperature;
    }
    public int getTemperature() {
        return temperature;
    }
}
// In Source Packet in file except/ex6/TooColdException.java
class TooColdException extends TemperatureException {
    public TooColdException(int temperature) {
        super(temperature);
    }
}
// In Source Packet in file except/ex6/TooHotException.java
class TooHotException extends TemperatureException {
    public TooHotException(int temperature) {
        super(temperature);
    }
}

                    


Given a TemperatureException family as defined above, catch clauses can query the exception object to find out the precise temperature that caused the problem. The temperature field of the exception object must be set when the object is created, as in:

                        // In Source Packet in file except/ex6/VirtualPerson.java
class VirtualPerson {
    private static final int tooCold = 65;
    private static final int tooHot = 85;
    public void drinkCoffee(CoffeeCup cup) throws
        TooColdException, TooHotException {
        int temperature = cup.getTemperature();
        if (temperature <= tooCold) {
            throw new TooColdException(temperature);
        }
        else if (temperature >= tooHot) {
            throw new TooHotException(temperature);
        }
        //...
    }
    //...
}

                    


Wherever the exception is caught, the catch clause can easily determine the actual temperature of the coffee and act accordingly, as in:

                        // In Source Packet in file except/ex6/VirtualCafe.java
class VirtualCafe {
    public static void serveCustomer(VirtualPerson cust,
        CoffeeCup cup) {
        try {
            cust.drinkCoffee(cup);
            System.out.println("Coffee is just right.");
        }
        catch (TooColdException e) {
            int temperature = e.getTemperature();
            System.out.println("Coffee temperature is "
                + temperature + " degrees Celsius.");
            if (temperature > 55 && temperature <= 65) {
                System.out.println("Coffee is cooling off.");
                // Add more hot coffee...
            }
            else if (temperature > 0 && temperature <= 55) {
                System.out.println("Coffee is too cold.");
                // Give customer a new cup of coffee with the
                // proper temperature...
            }
            else if (temperature <= 0) {
                System.out.println("Coffee is frozen.");
                // Deal with an irate customer...
            }
        }
        catch (TooHotException e) {
            int temperature = e.getTemperature();
            System.out.println("Coffee temperature is "
                + temperature + " degrees Celsius.");
            if (temperature >= 85 && temperature < 100) {
                System.out.println("Coffee is too hot.");
                // Ask customer to let it cool a few minutes...
            }
            else if (temperature >= 100 && temperature < 2000) {
                System.out.println(
                    "Both coffee and customer are steamed.");
                // Deal with an irate customer...
            }
            else if (temperature >= 2000) {
                System.out.println(
                    "The coffee is plasma.");
                // Deal with a very irate customer...
            }
        }
    }
}

                    


The program could deal with the temperature problem differently depending upon the coffee's actual temperature. If the coffee is just a little cold, the program could add more hot coffee to the cup. If the coffee is so cold that the customer's lips were instantly frozen to the cup, alternative measures could be taken.

Exceptions and the method invocation stack
Code inside a try block is in a sense surrounded by the catch clauses associated with the try block. When an exception is thrown, the surrounding catch clauses are examined in inside-out order. You can nest try blocks inside try blocks, in effect building up more and more layers of catch clauses that surround the code. When a method is invoked from within a try block, the catch clauses associated with that try block surround the code in the invoked method as well. If that method has try blocks and catch clauses, they are added as inner surrounding layers. What this means is that an exception may be thrown far up the method invocation stack before landing in a catch clause that can handle it.

As an example, consider the following exception classes, which are simpler versions of exceptions introduced in examples above:

                        // In Source Packet in file except/ex7/TemperatureException.java
class TemperatureException extends Exception {
}
// In Source Packet in file except/ex7/TooColdException.java
class TooColdException extends TemperatureException {
}
// In Source Packet in file except/ex7/TooHotException.java
class TooHotException extends TemperatureException {
}
// In Source Packet in file except/ex7/UnusualTasteException.java
class UnusualTasteException extends Exception {
}

                    


When the drinkCoffee() method of class VirtualPerson is invoked, it throws one of these four exceptions, chosen at random:

                        // In Source Packet in file except/ex7/VirtualPerson.java
class VirtualPerson {
    public void drinkCoffee(CoffeeCup cup) throws TooColdException,
        TemperatureException, UnusualTasteException {
        try {
            int i = (int) (Math.random() * 4.0);
            switch (i) {
            case 0:
                throw new TooHotException();
            case 1:
                throw new TooColdException();
            case 2:
                throw new UnusualTasteException();
            default:
                throw new TemperatureException();
            }
        }
        catch (TooHotException e) {
            System.out.println("This coffee is too hot.");
            // Customer will wait until it cools to an
            // acceptable temperature.
        }
    }
    //...
}

                    


If variable i in the drinkCoffee() method above happens to be set to a value of 0 the switch statement will instantiate and throw a TooHotException. Because the switch statement itself is enclosed within a try block that has a catch clause for TooHotException, execution continues at that catch clause. The program prints out:

                        This coffee is too hot.

                    


If variable i in the drinkCoffee() method above happens to be set to the value of 1, the switch statement will instantiate and throw a TooColdException. When this exception is thrown, the Java virtual machine will first check the catch clauses of the try block that surrounds the switch statement. In this case, however, no catch clause matches the thrown exception.

Because the TooColdException is not caught by the drinkCoffee() method, the Java virtual machine throws the exception up the method invocation stack to the method that invoked drinkCoffee(). As used here, a method invocation stack (or call stack) is a list of the methods that have been invoked by a thread, starting with the first method the thread invoked and ending with the current method. A method invocation stack shows the path of method invocations a thread took to arrive at the current method.

A graphical representation of the method invocation stack for drinkCoffee() is shown in Figure 3. In this figure, the method invocation stack is shown on the right and the corresponding Java stack is shown on the left. The Java stack is where methods keep their state inside the Java virtual machine. Each method gets a stack frame (or frame), which is pushed onto the stack when the method is invoked and popped from the stack when the method completes. The frame is an area in memory that contains the method's local variables, parameters, return value, and other information needed by the Java virtual machine to execute the method. In Figure 3, the stack is shown growing downwards. The top of the stack is at the bottom of the picture.

 

Figure 3. The method invocation stack for drinkCoffee()

When a method completes by executing a return statement, or by successfully executing the last statement in a method declared as void, it is said to complete normally. The Java virtual machine pops the returning method's stack frame, and continues executing just after the method invocation in the calling method. The calling method becomes the current method and its stack frame becomes the current frame.

When a method throws an exception that it doesn't catch itself, it is said to complete abruptly. Methods do not return a value when they complete abruptly, though they do pass along an exception object.

For example, when the drinkCoffee() method throws a TooColdException, it completes abruptly. Because the exception isn't caught by drinkCoffee(), the Java virtual machine pops drinkCoffee()'s stack frame. It then examines the next method up the invocation stack, in this case the serveCustomer() method of VirtualCafe, to see if it has a catch clause prepared to handle the exception.

Here's the code for VirtualCafe:

                        // In Source Packet in file except/ex7/VirtualCafe.java
class VirtualCafe {
    public static void serveCustomer(VirtualPerson cust,
        CoffeeCup cup)throws TemperatureException,
        UnusualTasteException {
        try {
            cust.drinkCoffee(cup);
        }
        catch (TooColdException e) {
            System.out.println("This coffee is too cold.");
            // Add more hot coffee...
        }
    }
}

                    


The serveCustomer() method above does indeed surround its invocation of drinkCoffee() with a try block that has an attached catch clause for TooColdException. So the exception stops here. The Java virtual machine makes the serveCustomer() method's stack frame current and continues execution at the first statement inside the catch clause. The program prints out:

                        This coffee is too cold.

                    


If variable i in the drinkCoffee() method above happens to be set to the value of 2, the switch statement will instantiate and throw an UnusualTasteException. When this exception is thrown, the Java virtual machine will first check the catch clauses of the try block that surrounds the switch statement. In this case, no catch clause matches the thrown exception. The virtual machine will then pop drinkCoffee()'s stack frame and examine the serveCustomer() method. But in serveCustomer(), no catch clause attached to the try block matches the thrown exception either. The virtual machine will therefore pop serveCustomer()'s stack frame and examine the next method up the invocation stack: the main() method of class Example7.

Here's the code for Example7:

                        // In Source Packet in file except/ex7/Example7.java
class Example7 {
    public static void main(String[] args)
        throws TemperatureException {
        // Create a new coffee cup.
        CoffeeCup cup = new CoffeeCup();
        // Create and serve a virtual customer.
        try {
            VirtualPerson cust = new VirtualPerson();
            VirtualCafe.serveCustomer(cust, cup);
        }
        catch (UnusualTasteException e) {
            System.out.println("This coffee has an unusual taste.");
        }
    }
}

                    


This main() method was farsighted enough to surround its invocation of serveCustomer() with a try block that includes a catch clause for UnusualTasteException. Thus, the Java virtual machine will make the main() method's stack frame current and will continue execution at the first statement in the catch clause. The program will print:   Continued  

目录
打赏
0
0
0
0
14
分享
相关文章
|
5月前
|
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
169 1
如何避免 Java 中的 TimeoutException 异常
在Java中,`TimeoutException`通常发生在执行操作超过预设时间时。要避免此异常,可以优化代码逻辑,减少不必要的等待;合理设置超时时间,确保其足够完成正常操作;使用异步处理或线程池管理任务,提高程序响应性。
325 13
【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常
在BeetISQL 2.13.8版本中,客户使用batch insert向yashandb表插入数据并尝试获取自动生成的sequence id时,出现类型转换异常。原因是beetlsql在prepareStatement时未指定返回列,导致yashan JDBC驱动返回rowid(字符串),与Java Bean中的数字类型tid不匹配。此问题影响业务流程,使无法正确获取sequence id。解决方法包括:1) 在batchInsert时不返回自动生成的sequence id;2) 升级至BeetISQL 3,其已修正该问题。
【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常
|
5月前
|
在 Java 中,如何自定义`NumberFormatException`异常
在Java中,自定义`NumberFormatException`异常可以通过继承`IllegalArgumentException`类并重写其构造方法来实现。自定义异常类可以添加额外的错误信息或行为,以便更精确地处理特定的数字格式转换错误。
83 1
【YashanDB知识库】yasdb jdbc驱动集成druid连接池,业务(java)日志中有token IDENTIFIER start异常
客户Java日志中出现异常,影响Druid的merge SQL功能(将SQL字面量替换为绑定变量以统计性能),但不影响正常业务流程。原因是Druid在merge SQL时传入null作为dbType,导致无法解析递归查询中的`start`关键字。
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
185 14
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
419 5
怎样避免 Java 中的 NoSuchFieldError 异常
在Java中避免NoSuchFieldError异常的关键在于确保类路径下没有不同版本的类文件冲突,避免反射时使用不存在的字段,以及确保所有依赖库版本兼容。编译和运行时使用的类版本应保持一致。
213 8
如何避免在 Java 中出现 NoSuchElementException 异常
在Java中,`NoSuchElementException`通常发生在使用迭代器、枚举或流等遍历集合时,尝试访问不存在的元素。为了避免该异常,可以在访问前检查是否有下一个元素(如使用`hasNext()`方法),或者使用`Optional`类处理可能为空的情况。正确管理集合边界和条件判断是关键。
183 6
|
5月前
|
Java异常捕捉处理和错误处理
Java异常捕捉处理和错误处理
121 1
下一篇
oss创建bucket
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等