Effective Java notes (27) eliminate unchecked warnings

        When programming with generics, you will encounter multiple compiler warnings: unchecked cast warning, unchecked method call warning, unchecked parameterized vararg type warning, and unchecked conversion warning. As you become more familiar with generics, you will encounter fewer and fewer warnings, but don't expect to compile correctly when you start writing code with generics.

        There are many unchecked warnings that are easy to eliminate. For example, suppose you accidentally write a statement like this:

Set<Lark> exaltation = new HashSet();

        The compiler will alert you in detail where things went wrong:

        You can then correct the displayed errors and eliminate the warnings. Note that you don't have to actually specify the type parameter, just enclose it with the diamond operator ( < > ), introduced in Java 7. The compiler then infers the correct actual type parameter (in this case Lark):

Set<Lark> exaltation = new HashSet<>();

        Some warnings are very difficult to dismiss. This article focuses on examples of such warnings. When you come across a warning that requires some thought, hold on! Eliminate every unchecked warning possible . If you eliminate all warnings, you can ensure that your code is type-safe which is a great thing. This means that there will be no ClassCastException exception at runtime, and you will be more confident that your program can achieve the expected function.

        If it is not possible to suppress the warning, and it can be proven that the code causing the warning is type-safe, (and only in this case) it is possible to suppress the warning with a @SuppressWarnings ("unchecked") annotation . If you don't first prove that your code is type-safe before suppressing the warning, you're just giving yourself a false sense of security. Code may compile without any warnings, but it will still throw a ClassCastException at runtime. But if you ignore (rather than suppress) unchecked warnings that you know are safe, you won't notice when a really problematic new warning appears. New warnings will drown out all false warnings.

        The SuppressWarnings annotation can be used at any level of granularity, from individual local variable declarations to entire classes. The SuppressWarnings annotation should always be used in the smallest possible scope . It's usually a variable declaration, or a very short method or constructor. Never use SuppressWarnings on an entire class, doing so may obscure important warnings.

        If you find yourself using the SuppressWarnings annotation in a method or constructor that is longer than one line, move it to a local variable declaration. Although you have to declare a new local variable, it's worth it. For example, look at the toArray method in the ArrayList class:

public <T> T[] toArray(T[] a) {
     if (a.length < size)
        return (T[]) Arrays.copyOf(elements, size, a.getClass());
     System.arraycopy(elements, 0, a, 0, size);
     if (a.length > size)
        a[size] = null;
     return a;
}

        If ArrayList is compiled, this method will generate this warning:

        It is legal to put the SuppressWarnings annotation in the return statement because it is not a statement. You can try to put the annotation on the whole method, but don't do it in practice, instead declare a local variable to hold the return value, and annotate its declaration, like this:

    public <T> T[] toArray(T[] a) {
        if (a.length < size) {
            // This cast is correct because the array we're creating
            // is of the same type as the one passed in,which is T[] .
            @SuppressWarnings ("unchecked") T result =
                    (T[]) Arrays . copyOf(elements, size, a.getClass()) ;
            return result;
        }
        System. arraycopy(elements, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

        This method compiles correctly, and the scope for suppressing unchecked warnings is minimized.

        Whenever using the SuppressWarnings ("unchecked") annotation, add a note explaining why it is safe to do so . This helps others understand the code, and more importantly, minimizes the chances of someone else modifying the code and making the computation unsafe. If you think this kind of comment is difficult to write, think about it. Eventually you will find that unchecked operations are very unsafe.

        All in all, unchecked warnings are important, don't ignore them. Each warning indicates that a ClassCastException may be thrown at runtime. Do your best to eliminate these warnings. If the unchecked warning cannot be eliminated, and it can be proved that the code causing the warning is type-safe , the @SuppressWarnings("unchecked") annotation can be used to suppress the warning in as small a scope as possible . Use a comment to document the reason for suppressing the warning.

Guess you like

Origin blog.csdn.net/java_faep/article/details/132149909