Effective Java (Exception handling) _java

Source: Internet
Author: User

57. Use exceptions only for exceptional situations:

I don't know if you've met the following code:

Copy Code code as follows:

try {
int i = 0;3
while (true)
Range[i++].climb ();
}
catch (ArrayIndexOutOfBoundsException e) {
}

The intent of this code is not so obvious that it is meant to traverse every element in the range of the variable array and to perform the climb method of the element, which throws the arrayindexoutofboundsexception exception directly when it exceeds the array length of the range. The catch code block catches the exception, but does nothing, but treats the error as part of the normal workflow. This kind of writing does give people a kind of incredible feeling, let us look at the revised wording:
Copy Code code as follows:

for (mountain M:range) {
M.climb ();
}

The readability is self-evident compared with the previous ones. So why would anyone use the first one? Apparently they were misled, and they tried to avoid the for-each of the JVM's Cross-border checks for each array access in the loop. This is no doubt superfluous, even counterproductive, because putting code in a try-catch block instead of some specific optimizations of the JVM, as with array bounds checking, is now optimized for many JVM implementations. In the actual test, we will find that the exception in the way its operation efficiency is much slower than the normal way.
In addition to the efficiency and code readability issues just mentioned, the first one will cover up some potential bugs, assuming that an array is also accessed in the climb method of the array element, and that the array is out of bounds during the access, based on the error, The JVM will throw a arrayindexoutofboundsexception exception, which, unfortunately, will be caught by a catch statement outside of the climb function, followed by the normal process after no processing, so that the bug is hidden.
The lesson of this example is simple: "Exceptions should be used only in the case of exceptions, they should never be used for normal control flow." Even though some people may say that this bizarre writing can lead to performance improvements, the performance advantage of this anomaly pattern cannot be maintained as the platform continues to improve. However, the subtle bugs of this overly intelligent model, and the pain of maintenance, remain.
Based on this principle, we will also be inspired when designing APIs. A well-designed API should not * * Its clients use exceptions for normal control flow. If ITERATOR,JDK is fully aware of this at design time, the client needs to invoke the Hasnext method to confirm that there is a readable collection element before executing the next method, see the following code:

Copy Code code as follows:

for (Iterator i = Collection.iterator (); I.hasnext ();) {
Foo f = i.next ();
}

If the iterator is missing the Hasnext method, the client changes the * * to the following:
Copy Code code as follows:

try {
Iterator i = Collection.iterator ();
while (true)
Foo f = i.next ();
}
catch (Nosuchelementexception e) {
}

This should be very similar to the example of traversing an array given at the beginning of this entry. In the actual design there is another way of validating the recognizable error return value, which is not appropriate for this example, because it may be legal for next to return NULL. So what are the differences between the two design methods in practical applications?
1. If there is a lack of concurrent access for synchronization, or can be changed by the outside world, it is necessary to use a method that recognizes the return value, because there is a time window between the test state (Hasnext) and the corresponding call (next), in which the object may change state. Therefore, in this case, you should choose how you want to return the recognized error return value.
2. If the state test method (Hasnext) and the corresponding invocation method (next) Use the same code, and for performance reasons, there is no need to repeat the same work two times, you should choose a way to return the recognized error return value.
3. For other scenarios, you should consider the design of the status test as much as possible, as it provides better readability.

58. Use the exception for the recoverable condition, use Run-time exception for programming error:


      Java provides three types of throw structures: Client exceptions, Run-time exceptions, and errors. This entry gives a general principle for these three types of scenarios that apply.
      1. If you expect the caller to recover appropriately, you should use an exception for this situation, such as if someone is planning to shop online and the resulting balance is insufficient, you can throw a custom client exception. By throwing a tested exception, the * * Caller handles the exception in a catch clause, or continues to propagate upward. Therefore, declaring a client exception in a method is a potential hint to the API user.
      2. Use run-time exceptions to indicate programming errors. Most run-time exceptions represent "prerequisite violations", where the user of the API does not comply with the usage conventions established by the API designer. Such issues as array access across borders.
      3. For errors, it is usually reserved for the JVM to indicate a lack of resources, a constraint failure, or other conditions that make the program unable to continue execution.
      for custom-tested exceptions, this entry gives a very practical tip that when the caller catches the exception, you can get more specific error information by invoking the interface method provided by the custom exception. Information such as current balance.

59, avoid unwanted usage of exceptions:

      Client exceptions are a good feature of Java's offering. Unlike return values, they are * * Programmers must handle exception conditions, which greatly enhance the reliability of the program. However, excessive use of the tested exception will make the API very inconvenient to use, after all, we still need to use some extra code to handle these thrown exceptions, and if the five APIs that it calls in a function throw an exception, writing such a function code would be a frustrating task.
      If the proper use of APIs does not prevent the creation of such exceptional conditions, and once an exception is generated, programmers using the API can take useful actions immediately, a burden that is considered justified. Unless both of these conditions are true, it is more appropriate to use an unhandled exception, as shown in the following test:

Copy Code code as follows:

try {
DoSomething ();
catch (Thecheckedexception e) {
throw new Assertionerror ();
}

try {
Donsomething ();
catch (Thecheckedexception e) {
E.printstacktrace ();
System.exit (1);
}

When we use a sample exception, it is recommended that you consider using an unhandled exception if the exception is handled in a catch clause as if it were just two examples or worse. The reason is simple, they do not make any action to restore the exception in the catch clause.

60, priority use of standard exceptions:


By using standard exceptions, you can not only better reuse existing code, but also make the API you design easier to learn and use because it is more consistent with the idioms that programmers already know. Another advantage is that code is more readable, and programmers do not have more unfamiliar code when they read. This entry gives some very common and easily reused exceptions, as shown in the following table:
Unusual application situations
The IllegalArgumentException parameter value is not valid.
IllegalStateException the object state is not appropriate for a method invocation.
NullPointerException the parameter value is NULL when NULL is prohibited.
indexoutofboundsexception subscript parameter values out of bounds
Concurrentmodificationexception detects concurrent modifications to objects when concurrent modifications are prohibited.
The Unsupportedoperationexception object does not support the method requested by the user.
Of course, there are many other anomalies in Java, such as ArithmeticException, NumberFormatException, and so on, these exceptions have their own application, however, it should be noted that these anomalies in the application of occasions at some time the boundaries are not very distinct, As for the choice of which is more appropriate, then more need to rely on the context of the environment to judge.
Finally, it is important to ensure that the condition that throws the exception is consistent with the conditions described in the exception document.

61, throw the exception corresponding to the abstract:


This situation can be confusing if the exception thrown by the method has no obvious relationship to the task it performs. Especially when an exception is thrown from the bottom, if no processing is done at the middle tier, the low-level implementation details will directly contaminate the top-level API interface. To solve such problems, we usually do the following:

Copy Code code as follows:

try {
Dolowerleverthings ();
catch (Lowerlevelexception e) {
throw new Higherlevelexception (...);
}

This approach is called anomalous translation. In fact, a more convenient form of translation-the exception chain-is also provided in Java. Imagine the above example code, in the debugging phase, if the high-level application logic can learn the underlying causes of the actual exception, then to find the root cause of the problem will be very helpful, see the following code:
Copy Code code as follows:

try {dolowerlevelthings ();
catch (Lowerlevelexception cause) {
throw new higherlevelexception (cause);
}

The underlying exception is passed as a parameter to a high-level exception, and the constructor for the exception chain is supported for most standard exceptions, and if not, the Throwable Initcause method can be used to set the cause. The exception chain not only allows you to access the reason through the interface function, it can also integrate the getcause of the cause into the higher level of the exception.
Through this kind of abnormal chain, it is very effective to completely separate the low-level implementation details from the high-level application logic.

63, in the details include the ability to capture the failure of information:


When a program fails due to an exception that has not been caught, the system automatically prints out the stack trajectory of the exception. The string representation of the exception in the stack trajectory, that is, the return result of the ToString method. If we provide a detailed error message for this exception at this time, it is extremely meaningful for both the error location and the traceability. For example, we format the input parameters of the function that throws the exception and the field value of the class that contains the function, and then package the exception object to be thrown. Assuming that our high level application catches the indexoutofboundsexception exception, if the exception object can now carry the lower and upper bounds of the array and the subscript values that are currently out of bounds, after seeing this information, we can quickly make the correct judgment and revise the bug.
In particular, for a client exception, it is important that the exception type thrown can provide additional interface methods for obtaining the data or information that is causing the error, which is critical for the error recovery of the calling function that captures the exception.

64. Try to keep the failure atomic:


This is a very important suggestion, because in actual development when you are the developer of the interface, often ignore him, think no assurance of the estimate is not a problem. On the contrary, if you are the user of the interface, you will also ignore him, and think that this is what the interface implementation is rightfully done.
After an object throws an exception, we usually expect the object to remain in a well-defined, usable state, even if the failure occurs during an operation. This is especially important for an exception to be tested because the caller expects to recover from this exception. In general, a failed method call should keep the object in the state before it was invoked. A method with this property is called "Failed atomicity".
There are several ways to maintain this atomic nature.
1. The easiest way is to design immutable objects. Because a failed operation will only cause the creation of the new object to fail without affecting the existing object.
2. For a Mutable object, the general method is to validate the parameters before manipulating the object, which causes the object to throw a more significant exception before it is modified, such as:

Copy Code code as follows:

Public Object pop () {
if (size = = 0)
throw new Emptystackexception ();
Object result = Elements[--size];
Elements[size] = null;
return result;
}

An exception is thrown if the size,elements array is not validated before the operation, but the value of size has changed, and the object will never revert to its normal state after it has been used.
3. Pre-write recovery code, in the case of error execution band code, because this method in code writing and code maintenance process, will bring a lot of maintenance costs, coupled with relatively low efficiency, so rarely use this method.
4. Create a temporary copy of the object, and reinitialize the current object's state with the replicated object once an exception occurs during the operation.
Although it is generally desirable to achieve failure atomicity, in some cases it is difficult to do so, as two threads simultaneously modify a mutable object and, in the absence of good synchronization, once the concurrentmodificationexception exception is thrown, It's hard to get back to the original state.

65, do not ignore the exception:

This is an obvious common sense, but it is often violated, so the entry is again presented to it, such as:

Copy Code code as follows:

try {
DoSomething ();
catch (Someexception e) {
}

A predictable, negligible exception can be used when the FileInputStream is closed because the data is already read. Even so, if you output a hint when you catch the exception, this can be helpful in digging out some potential problems. Otherwise, some potential problems will remain hidden until a sudden burst of time, causing irreparable consequences.
The recommendations in this entry also apply to the exceptions that are inspected and those that have not been inspected.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.