Thursday, 14 July 2011

The Value of String.valueOf

Most Java developers have probably had their fill of NullPointerException. Most of us have learned the value of doing certain things to reduce our "opportunities" of encountering the NullPointerException. Indeed, there is a Wiki page dedicated to preventing or reducing NullPointerExceptions.

Several people have argued for additional language support for improved and easier handling of potential null. These include Java SE 7 proposals, Optimized Null Check, and Kinga Dobolyi's thesis Changing Java’s Semantics for Handling Null Pointer Exceptions.

Among the many things we can already do rather easily to reduce our encounters with NullPointerException, one particular easy thing to do is to apply String.valueOf(Object) when appropriate. The String.valueOf(Object) method, as its Javadoc-generated documentation states, returns "null" if the passed in object is null and returns the results on the passed-in Object's toString() call if the passed-in Object is not null. In other words, String.valueOf(String) does the null checking for you.

The use of String.valueOf(Object) is particularly useful when implementing toString methods on custom classes. Because most toString implementations provide the class's data members in String format, String.valueOf(Object) is a natural fit. All Java objects based on classes that extend Object provide a toString() implementation even if it is simply their parent's (or even Object's) implementation of toString(). However, if a member class implements toString but the member itself is null rather than an instance of the class, then the toString() does no good (and actually leads to a NullPointerException when called).

This is demonstrated with the following example code.

Consider a class called PersonName, which holds last name and first name of the person:

package com.vaani.string;

/**
* Class upon which to call toString.
*/
public class PersonName
{
private String lastName;
private String firstName;

public PersonName(final String newLastName, final String newFirstName)
{
lastName = newLastName;
firstName = newFirstName;
}

/**
* Provide String representation of me.
*
* @return My String representation.
*/
@Override
public String toString()
{
return firstName + " " + lastName;
}
}


Person.java


package com.vaani.string;



public class Person
{
private PersonName name;

public Person( PersonName newName)
{
name = newName;
}



/**
* Provide String representation of me.
*
* @return My String representation.
*/
public String toString()
{
//to be implemented
}
}


Now this person.java has toString() which is to be implemented, but we will see how it throws NPE. Consider the main method:


PersonName personName = new PersonName("Flintstone", null);
//print personname as string
System.out.println("Person's Name [DIRECT]: " + personName);
System.out.println("Person's Name [TOSTRING]: " + personName.toString());
System.out.println("Person's Name [STRING.VALUEOF]: " + String.valueOf(personName));
Output will be:

Person's Name         [DIRECT]: null Flintstone
Person'
s Name [TOSTRING]: null Flintstone
Person's Name [STRING.VALUEOF]: null Flintstone

Now consider the toString() func is represented as

Also if we call Person's constructor with personName(instance created above), everything will still be fine:

PersonName name;
//code skipped
public String toString()
{
// Don't use -- can lead to runtime error (NullPointerException)
return name.toString();
}

Now as we did earlier:

PersonName personName = new PersonName("Flintstone", null);

//create next object from personName
Person personOne = new Person(personName);
System.out.println("Person One [DIRECT]: " + personOne);
System.out.println("Person One [TOSTRING]: " + personOne.toString());
System.out.println("Person One [STRING.VALUEOF]: " + String.valueOf(personOne));

This will work fine because of personName will return its toString() func, and dont throw any NPE. But this will result in bang:

Person personTwo = new Person(null);
System.out.println("Person Two [DIRECT]: " + personTwo);
System.out.println("Person Two [TOSTRING]: " + personTwo.toString());
System.out.println("Person Two [STRING.VALUEOF]: " + String.valueOf(personTwo));
Each of this above line throws exception. So please be aware of this. To avoid null pointer exception you can implement toString() func of Person like this:

public String toString()
{
// It's all good
return String.valueOf(name);
}
Now the personTwo will be printed as null.
Full code listing for Person.java(personName.java is already covered):

package com.vaani.string;



public class Person
{
private PersonName name;

public Person( PersonName newName)
{
name = newName;
}



/**
* Provide String representation of me.
*
* @return My String representation.
*/
public String toString()
{
// Don't use -- leads to compiler time error (incompatible types)
//return name;

// Don't use -- can lead to runtime error (NullPointerException)
//return name.toString();

// It's all good
return String.valueOf(name);
}
}

main method to run this code:

package com.vaani.string;

import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Logger;

/**
* Example class demonstrating use of String representations available through
* implicit String, toString(), and String.valueOf().
*/
public class StringValueFunc
{
private static final String NEW_LINE = System.getProperty("line.separator");

/** Using java.util.logging. */
private static Logger LOGGER = Logger.getLogger(
StringValueFunc.class.getName());

/**
* Main function for running tests/demonstrations.
*
* @param arguments Command-line arguments; none anticipated.
*/
public static void main(final String[] arguments)
{
//takes last name and first name
PersonName personName = new PersonName("Flintstone", null);

//create next object from personName
Person personOne = new Person(personName);
//just initiate to null
Person personTwo = new Person(null);
printHeader("String representation of direct Strings", System.out);

System.out.println("Person's Name [DIRECT]: " + personName);
System.out.println("Person's Name [TOSTRING]: " + personName.toString());
System.out.println("Person's Name [STRING.VALUEOF]: " + String.valueOf(personName));
printBlankLine(System.out);

printHeader("String representation of non-null complex object", System.out);

System.out.println("Person One [DIRECT]: " + personOne);
System.out.println("Person One [TOSTRING]: " + personOne.toString());
System.out.println("Person One [STRING.VALUEOF]: " + String.valueOf(personOne));
printBlankLine(System.out);

printHeader("String representation of null complex object", System.out);

System.out.println("Person Two [DIRECT]: " + personTwo);
System.out.println("Person Two [TOSTRING]: " + personTwo.toString());
System.out.println("Person Two [STRING.VALUEOF]: " + String.valueOf(personTwo));
printBlankLine(System.out);
}

public static void printHeader(final String message, final OutputStream out)
{
final String headerSeparator =
"====================================================================";

try
{
out.write((headerSeparator + NEW_LINE + message + NEW_LINE).getBytes());
out.write((headerSeparator + NEW_LINE).getBytes());
}
catch (IOException ioEx)
{
System.out.println(headerSeparator);
System.out.println(message);
System.out.println(headerSeparator);
LOGGER.warning("Could not write header information to provided OutputStream.");
}
}

public static void printBlankLine(final OutputStream out)
{
try
{
out.write(NEW_LINE.getBytes());
}
catch (IOException ioEx)
{
System.out.println(NEW_LINE);
LOGGER.warning("Could not write blank line to provided OutputStream.");
}
}


}

The above code can be used to demonstrate building of a toString method on a complex object and how its behaves when called by an owning class. The method of most interest is at the bottom of the code shown above. Two return values are commented out because of problems associated with them. The final example, using String.valueOf(Object) is NOT commented out because it works the best each time it is run whether or not the complex PersonName object is null. The next three images show the output for each of these presentations of the Person objects' String representations.











Finally, the String class provides many overloaded valueOf methods. In addition to the version that was the focus of this blog post (accepts an Object), the other overloaded versions of valueOf accept primitive data types and arrays of primitive data types.
Conclusion
Regardless of what the future brings in terms of improved null handling in Java, there are many tactics we can take today to reduce the unwanted (sometimes we actually do want them thrown!) occurrences of NullPointerException. One of these is to use String.valueOf(Object) when appropriate.

Additional Resources

Effective Java : How to Avoid NPE / Null Pointer Exception in java?

It doesn't take much Java development experience to learn firsthand what the NullPointerException is about. In fact, one person has highlighted dealing with this as the number one mistake Java developers make. I blogged previously on use of String.value(Object) to reduce unwanted NullPointerExceptions. There are several other simple techniques one can use to reduce or eliminate the occurrences of this common type of RuntimeException that has been with us since JDK 1.0. This blog post collects and summarizes some of the most popular of these techniques.

Check Each Object For Null Before Using

The most sure way to avoid a NullPointerException is to check all object references to ensure that they are not null before accessing one of the object's fields or methods. As the following example indicates, this is a very simple technique.

final String causeStr = "adding String to Deque that is set to null.";
final String elementStr = "Fudd";
Deque<String> deque = null;

try
{
deque.push(elementStr);
log("Successful at " + causeStr, System.out);
}
catch (NullPointerException nullPointer)
{
log(causeStr, nullPointer, System.out);
}

try
{
if (deque == null)
{
deque = new LinkedList<String>();
}
deque.push(elementStr);
log( "Successful at " + causeStr
+ " (by checking first for null and instantiating Deque implementation)",
System.out);
}
catch (NullPointerException nullPointer)
{
log(causeStr, nullPointer, System.out);
}

In the code above, the Deque used is intentionally initialized to null to facilitate the example. The code in the first try block does not check for null before trying to access a Deque method. The code in the second try block does check for null and instantiates an implementation of the Deque (LinkedList) if it is null. The output from both examples looks like this:

ERROR: NullPointerException encountered while trying to adding 
String to Deque that is set to null.
java.lang.NullPointerException
INFO: Successful at adding String to Deque that is set to null.
(by checking first for null and instantiating Deque implementation)

The message following ERROR in the output above indicates that a NullPointerException is thrown when a method call is attempted on the null Deque. The message following INFO in the output above indicates that by checking Deque for null first and then instantiating a new implementation for it when it is null, the exception was avoided altogether.

This approach is often used and, as shown above, can be very useful in avoiding unwanted (unexpected) NullPointerException instances. However, it is not without its costs. Checking for null before using every object can bloat the code, can be tedious to write, and opens more room for problems with development and maintenance of the additional code. For this reason, there has been talk of introducing Java language support for built-in null detection, automatic adding of these checks for null after the initial coding, null-safe types, use of Aspect-Oriented Programming (AOP) to add null checking to byte code, and other null-detection tools.

Groovy already provides a convenient mechanism for dealing with object references that are potentially null. Groovy's safe navigation operator (?.) returns null rather than throwing a NullPointerException when a null object reference is accessed.

Because checking null for every object reference can be tedious and does bloat the code, many developers choose to judiciously select which objects to check for null. This typically leads to checking of null on all objects of potentially unknown origins. The idea here is that objects can be checked at exposed interfaces and then be assumed to be safe after the initial check.

This is a situation where the ternary operator can be particularly useful. Instead of
// retrieved a BigDecimal called someObject
String returnString;
if (someObject != null)
{
returnString = someObject.toEngineeringString();
}
else
{
returnString = "";
}

the ternary operator supports this more concise syntax

// retrieved a BigDecimal called someObject
final String returnString = (someObject != null)
? someObject.toEngineeringString()
: "";
}

Check Method Arguments for Null

The technique just discussed can be used on all objects. As stated in that technique's description, many developers choose to only check objects for null when they come from "untrusted" sources. This often means testing for null first thing in methods exposed to external callers. For example, in a particular class, the developer might choose to check for null on all objects passed to public methods, but not check for null in private methods.

The following code demonstrates this checking for null on method entry. It includes a single method as the demonstrative method that turns around and calls two methods, passing each method a single null argument. One of the methods receiving a null argument checks that argument for null first, but the other just assumes the passed-in parameter is not null.

/**
    * Append predefined text String to the provided StringBuilder.
    *
    * @param builder The StringBuilder that will have text appended to it; should
    * be non-null.
    * @throws IllegalArgumentException Thrown if the provided StringBuilder is
    * null.
    */
private void appendPredefinedTextToProvidedBuilderCheckForNull(
final StringBuilder builder)
{
if (builder == null)
{
throw new IllegalArgumentException(
"The provided StringBuilder was null; non-null value must be provided.");
}
builder.append("Thanks for supplying a StringBuilder.");
}

/**
    * Append predefined text String to the provided StringBuilder.
    *
    * @param builder The StringBuilder that will have text appended to it; should
    * be non-null.
    */
private void appendPredefinedTextToProvidedBuilderNoCheckForNull(
final StringBuilder builder)
{
builder.append("Thanks for supplying a StringBuilder.");
}

/**
    * Demonstrate effect of checking parameters for null before trying to use
    * passed-in parameters that are potentially null.
    */
public void demonstrateCheckingArgumentsForNull()
{
final String causeStr = "provide null to method as argument.";
logHeader("DEMONSTRATING CHECKING METHOD PARAMETERS FOR NULL", System.out);

try
{
appendPredefinedTextToProvidedBuilderNoCheckForNull(null);
}
catch (NullPointerException nullPointer)
{
log(causeStr, nullPointer, System.out);
}

try
{
appendPredefinedTextToProvidedBuilderCheckForNull(null);
}
catch (IllegalArgumentException illegalArgument)
{
log(causeStr, illegalArgument, System.out);
}
}

When the above code is executed, the output appears as shown next.
ERROR: NullPointerException encountered while trying to provide null to 
method as argument.
java.lang.NullPointerException
ERROR: IllegalArgumentException encountered while trying to provide null
to method as argument.
java.lang.IllegalArgumentException: The provided StringBuilder was null;
non-null value must be provided.


In both cases, an error message was logged. However, the case in which a null was checked for threw an advertised IllegalArgumentException that included additional context information about when the null was encountered. Alternatively, this null parameter could have been handled in a variety of ways. For the case in which a null parameter was not handled, there were no options for how to handle it. Many people prefer to throw a NullPolinterException with the additional context information when a null is explicitly discovered (see Item #60 in the Second Edition of Effective Java or Item #42 in First Edition), but I have a slight preference for IllegalArgumentException when it is explicitly a method argument that is null because I think the very exception adds context details and it is easy to include "null" in the subject.

The technique of checking method arguments for null is really a subset of the more general technique of checking all objects for null. However, as outlined above, arguments to publicly exposed methods are often the least trusted in an application and so checking them may be more important than checking the average object for null.

Checking method parameters for null is also a subset of the more general practice of checking method parameters for general validity as discussed in Item #38 of the Second Edition of Effective Java (Item 23 in First Edition).


Consider Primitives Rather than Objects

I don't think it is a good idea to select a primitive data type (such as int) over its corresponding object reference type (such as Integer) simply to avoid the possibility of a NullPointerException, but there is no denying that one of the advantages of primitive types is that they do not lead to NullPointerExceptions. However, primitives still must be checked for validity (a month cannot be a negative integer) and so this benefit may be small. On the other hand, primitives cannot be used in Java Collections and there are times one wants the ability to set a value to null.

The most important thing is to be very cautious about the combination of primitives, reference types, and autoboxing. There is a warning in Effective Java (Second Edition, Item #49) regarding the dangers, including throwing of NullPointerException, related to careless mixing of primitive and reference types.


Carefully Consider Chained Method Calls

A NullPointerException can be very easy to find because a line number will state where it occurred. For example, a stack trace might look like that shown next:

java.lang.NullPointerException
at dustin.examples.AvoidingNullPointerExamples.
demonstrateNullPointerExceptionStackTrace(AvoidingNullPointerExamples.java:222)
at dustin.examples.
AvoidingNullPointerExamples.main(AvoidingNullPointerExamples.java:247)

The stack trace makes it obvious that the NullPointerException was thrown as a result of code executed on line 222 of AvoidingNullPointerExamples.java. Even with the line number provided, it can still be difficult to narrow down which object is null if there are multiple objects with methods or fields accessed on the same line.

For example, a statement like someObject.getObjectA().getObjectB().getObjectC().toString(); has four possible calls that might have thrown the NullPointerException attributed to the same line of code. Using a debugger can help with this, but there may be situations when it is preferable to simply break the above code up so that each call is performed on a separate line. This allows the line number contained in a stack trace to easily indicate which exact call was the problem. Furthermore, it facilitates explicit checking each object for null. However, on the downside, breaking up the code increases the line of code count (to some that's a positive!) and may not always be desirable, especially if one is certain none of the methods in question will ever be null.


Make NullPointerExceptions More Informative

In the above recommendation, the warning was to consider carefully use of method call chaining primarily because it made having the line number in the stack trace for a NullPointerException less helpful than it otherwise might be. However, the line number is only shown in a stack trace when the code was compiled with the debug flag turned on. If it was compiled without debug, the stack trace looks like that shown next:

java.lang.NullPointerException
at dustin.examples.AvoidingNullPointerExamples.
demonstrateNullPointerExceptionStackTrace(Unknown Source)
at dustin.examples.AvoidingNullPointerExamples.main(Unknown Source)

As the above output demonstrates, there is a method name, but not no line number for the NullPointerException. This makes it more difficult to immediately identify what in the code led to the exception. One way to address this is to provide context information in any thrown NullPointerException. This idea was demonstrated earlier when a NullPointerException was caught and re-thrown with additional context information as a IllegalArgumentException. However, even if the exception is simply re-thrown as another NullPointerException with context information, it is still helpful. The context information helps the person debugging the code to more quickly identify the true cause of the problem.

The following example demonstrates this principle.

final Calendar nullCalendar = null;

try
{
final Date date = nullCalendar.getTime();
}
catch (NullPointerException nullPointer)
{
log("NullPointerException with useful data", nullPointer, System.out);
}

try
{
if (nullCalendar == null)
{
throw new NullPointerException("Could not extract Date from provided Calendar");
}
final Date date = nullCalendar.getTime();
}
catch (NullPointerException nullPointer)
{
log("NullPointerException with useful data", nullPointer, System.out);
}

The output from running the above code looks as follows.

ERROR: NullPointerException encountered while trying to NullPointerException 
with useful data
java.lang.NullPointerException
ERROR: NullPointerException encountered while trying to
NullPointerException with useful data
java.lang.NullPointerException: Could not extract Date from provided Calendar

The first error does not provide any context information and only conveys that it is a NullPointerException. The second error, however, had explicit context information added to it which would go a long way in helping identify the source of the exception.


Use String.valueOf Rather than toString

As described previously, one of the surest methods for avoiding NullPointerException is to check the object being referenced for null first. The String.valueOf(Object) method is a good example of a case where this check for null can be done implicitly without any additional effort on the developer's part. I blogged on this previously, but include a brief example of its use here.

 


Source : Inspired by actual events

Stringifying Java Arrays

J2SE 5 provided significant new language features that made Java significantly easier to use and more expressive than it had ever been. Although "big" new J2SE 5 features such as enums, generics, and annotations, there was a plethora of new APIs and methods that have made our lives easier ever since. In this post, I briefly look at two of my favorites when dealing with Java arrays: the Arrays.toString(Object[]) method and the Arrays.deepToString(Object[]) method.

The Arrays class has been around since JDK 1.2, but the methods for conveniently and simply converting arrays to a readable String including relevant array content without using Arrays.asList() were added with J2SE 5. Both Arrays.toString(Object[]) and Arrays.deepToString(Object[]) are static methods that act upon the arrays provided to them. The former, Arrays.toString(Object[]), is intended for single-dimension arrays while the latter, Arrays.deepToString(Object[]), is intended for multi-dimensional arrays. As my example later in this post will demonstrate, the multi-dimension deepToString will produce expected results even for single-dimension arrays. The two methods also provide easy and safe null handling, something that I appreciate.

The next code listing is for a simple demonstration class that demonstrates trying to put the contents of various types of Java arrays into a String format. The types of arrays demonstrated are a single dimension array, a double dimensional array representing multi-dimensional arrays of various sizes, and an array that is really just null. The three methods demonstrated for getting a String out of these three types of arrays are (1) simple Object.toString() on each array (implicitly in case of null array to avoid the dreaded NullPointerException), (2) Arrays.toString(Object[]), and (3) Arrays.deepToString(Object[]).
package com.vaani.arraytest;

import java.util.Arrays;
import static java.lang.System.out;

/**
* Simple demonstration of Arrays.toString(Object[]) method and the
* Arrays.deepToString(Object[]) method.
*/
public class Array2String
{
/**
* Demonstrate usage and behavior of Arrays.toString(Object[]).
*/
private static void demonstrateArraysToString()
{
out.println(
"Single Dimension Arrays.toString: "
+ Arrays.toString(prepareSingleDimensionArray()));
out.println(
"Double Dimension Arrays.toString: "
+ Arrays.toString(prepareDoubleDimensionArray()));
out.println(
"Null Array Arrays.toString: "
+ Arrays.toString(prepareNullArray()));
}

/**
* Demonstrate usage and behavior of Arrays.deepToString(Object[]).
*/
private static void demonstrateArraysDeepToString()
{
out.println(
"Single Dimension Arrays.deepToString: "
+ Arrays.deepToString(prepareSingleDimensionArray()));
out.println(
"Double Dimension Arrays.deepToString: "
+ Arrays.deepToString(prepareDoubleDimensionArray()));
out.println(
"Null Array Arrays.deepToString: "
+ Arrays.deepToString(prepareNullArray()));
}

/**
* Demonstrate attempting to get String version of array with simple toString()
* call (not using Arrays class).
*/
private static void demonstrateDirectArrayString()
{
out.println("Single Dimension toString(): " + prepareSingleDimensionArray().toString());
out.println("Double Dimension toString(): " + prepareDoubleDimensionArray());
out.println("Null Array toString(): " + prepareNullArray());
}

/**
* Prepare a single-dimensional array to be used in demonstrations.
*
* @return Single-dimensional array.
*/
private static Object[] prepareSingleDimensionArray()
{
final String[] names = {"Aaron", "Bianca", "Charles", "Denise", "Elmer"};
return names;
}

/**
* Prepare a double-dimension array to be used in demonstrations.
*
* @return Double-dimensional array.
*/
private static Object[] prepareDoubleDimensionArray()
{
final Object[][] namesAndAges = {
{"Aaron", 10}, {"Bianca", 25}, {"Charles", 32}, {"Denise", 29}, {"Elmer", 67}};
return namesAndAges;
}

/**
* Prepare a null array.
*
* @return Array that is really null.
*/
private static Object[] prepareNullArray()
{
return null;
}

/**
* Main executable function for demonstrating Arrays.toString(Object[]) and
* Arrays.deepToString(Object[]) methods.
*/
public static void main(final String[] arguments)
{
out.println("\n\n\nDemonstrating direct array to string using toString():");
demonstrateDirectArrayString();

out.println("\n\n\nDemonstrating Arrays.toString() to get arrays as String:");
demonstrateArraysToString();

out.println("\n\n\nDemonstrating Arrays.deepToString() to get the String:");
demonstrateArraysDeepToString();
}
}


The above code exercises the three mentioned approaches for getting a String out of an array on the three different types of arrays: single dimension, multi dimension, and null array. The output from running this code demonstrates the utility of the different approaches. That output is shown next.

Demonstrating direct array to string using toString():
Single Dimension toString(): [Ljava.lang.String;@3e25a5
Double Dimension toString(): [[Ljava.lang.Object;@19821f
Null Array toString(): null
///////////
Demonstrating Arrays.toString() to get arrays as String:
Single Dimension Arrays.toString: [Aaron, Bianca, Charles, Denise, Elmer]
Double Dimension Arrays.toString: [[Ljava.lang.Object;@addbf1, [Ljava.lang.Object;@42e816, [Ljava.lang.Object;@9304b1, [Ljava.lang.Object;@190d11, [Ljava.lang.Object;@a90653]
Null Array Arrays.toString: null


///////////
Demonstrating Arrays.deepToString() to get the String:
Single Dimension Arrays.deepToString: [Aaron, Bianca, Charles, Denise, Elmer]
Double Dimension Arrays.deepToString: [[Aaron, 10], [Bianca, 25], [Charles, 32], [Denise, 29], [Elmer, 67]]
Null Array Arrays.deepToString: null

The code above and its corresponding output lead to several observations:



  1. Simple Object.toString() on arrays is seldom what we want as it only prints the String representation of the array itself and not of its contents.
  2. Arrays.toString(Object[]) will print a String representation for multi-dimensional arrays, but this representation suffers the same drawbacks as Object.toString() after the first dimension. The first dimension (and only dimension for a single dimension array) gets put into an expected String, but deeper dimensions have the same Object.toString() treatment.
  3. Arrays.deepToString(Object[]), while intended for multi-dimensional arrays, produces the expected results for both single and multi-dimensional arrays.
  4. Both Arrays.toString(Object[]) and Arrays.deepToString(Object[]) handle null array gracefully, simply returning a String "null".

I tend to use Java Collections far more than I use Java arrays. However, when I do need to work with arrays, it is nice to have the many useful features of the java.util.Arrays class. As this post has demonstrated, Arrays.toString(Object[]) and Arrays.deepToString(Object[]) are particularly valuable in obtaining a useful String representation of an array's contents. The java.util.Arrays class provides similar "deep" methods for performing equals and hashCode functionality on multi-dimensional arrays: Arrays.deepEquals and Arrays.deepHashCode.

javac's -Xprint Option

javac's -Xlint Options

The Java programming language compiler (javac) provided by Oracle (and formerly by Sun) has several non-standard options that are often useful. One of the most useful is the set of non-standard options that print out warnings encountered during compilation. That set of options is the subject of this post.

The javac page section on non-standard options lists and provides brief details on each of these options. The following is the relevant snippet from that page.

A listing of these options is also available from the command line (assuming the Java SDK is installed) with the command: javac -help -X. This is briefer than the man page/web page example shown above and is shown next.

As the previous snapshot from running javac -help -X indicates, the ten specific conditions for which Xlint warnings exist are (in alphabetical order): cast, deprecation, divzero, empty, fallthrough, finally, overrides, path, serial, and unchecked. I briefly look at each of these and provide a code snippet that leads to these warning occurring when Xlint is turned on. Note that the man page for javac and the Java SE 6 javac page both only list half of these Xlint options (documentation is apparently not as up-to-date as the javac usage/help). There is a useful NetBeans Wiki entry that summarizes all ten options.

The javac compiler allows all or none of the Xlint warnings to be enabled. If Xlint is not specified at all of the option -Xlint:none is explicitly specified, the behavior is to not show most of the warnings. Interestingly, the output does provide a warning about deprecation and unchecked warnings and recommends running javac with -Xlint enabled to see the details on these two types of warnings.

Before the end of this post, I'll demonstrate Java code that leads to 13 total reported Xlint warnings covering all ten of the options discussed above. However, without Xlint specified, the output is as shown in the next screen snapshot.

As the above image indicates, whether Xlint is not specified at all or is specified explicitly with "none", the result is the same: the majority of the warnings are not shown, but there are simple references to the deprecation and unchecked warnings with recommendations to run javac with -Xlint:deprecation and -Xlint:unchecked respectively for additional details. Running javac with -Xlint:all or -Xlint with no other options will show all warnings and would work to see the details regarding deprecated, unchecked, and all other applicable Xlint-enabled warnings. This will be shown after going through the source code and each Xlint warning individually.

-Xlint:cast
This option can be used to have the compiler warn the developer that a redundant cast is being made. Here is a code snippet that would get flagged if -Xlint, -Xlint:all, or -Xlint:cast was provided to javac when compiling the source.

/**
    * Demonstrates -Xlint:cast warning of a redundant cast.
    */
private static void demonstrateCastWarning()
{
final Set<Person> people = new HashSet<Person>();
people.add(fred);
people.add(wilma);
people.add(barney);
for (final Person person : people)
{
// Redundant cast because generic type explicitly is Person
out.println("Person: " + ((Person) person).getFullName());
}
}
In the above code, there is no need to cast the person object inside the for loop to Person and -Xlint:cast will warn of this unnecessary and redundant cast with a message stating something like:
src\vaani\examples\Main.java:37: warning: [cast] redundant cast to dustin.examples.Person
out.println("Person: " + ((Person) person).getFullName());

-Xlint:deprecation
As discussed above, the Xlint deprecation warning was evidently deemed important enough to justify it being advertised even when Xlint is not explicitly run. This warning occurs when a deprecated method is invoked. The following code example demonstrates such a case.

/** 
* Cause -Xlint:deprecation to print warning about use of deprecated method.
*/
private static void demonstrateDeprecationWarning()
{
out.println("Fred's full name is " + fred.getName());
}
You cannot tell without the source code for the Person class (of which "fred" is an instance), but that getName() method is deprecated in Person. The following output from running javac with -Xlint, -Xlint:all, or -Xlint:deprecation confirms that (or points it out if the developer missed it).

src\vaani\examples\Main.java:47: warning: [deprecation] getName() in dustin.examples.Person has been deprecated
out.println("Fred's full name is " + fred.getName());

-Xlint:divzero
The divzero Xlint option indicates when integral division divides by a literal zero. A code example that will demonstrate this is shown next:

/**
* Demonstrate -Xlint:divzero in action by dividing an int by a literal zero.
*/
private static void demonstrateDivideByZeroWarning()
{
out.println("Two divided by zero is " + divideIntegerByZeroForLongQuotient(2));
}

/**
* Divide the provided divisor into the provided dividend and return the
* resulting quotient. No checks are made to ensure that divisor is not zero.
*
* @param dividend Integer to be divided.
* @return Quotient of division of dividend by literal zero.
*/
private static long divideIntegerByZeroForLongQuotient(final int dividend)
{
// Hard-coded divisor of zero will lead to warning. Had the divisor been
// passed in as a parameter with a zero value, this would not lead to
// that warning.
return dividend / 0;
}
The output from javac when the above is compiled is now shown.


src\dustin\examples\Main.java:231: warning: [divzero] division by zero
return dividend / 0;
^
When I intentionally tried to force this warning, it seemed to only work for a hard-coded (literal) zero divisor. Also, it does not flag double division because Infinity can be returned as a valid answer in that case without throwing an exception.
-Xlint:empty
The purpose of -Xlint:empty is to notify the developer that an "empty" if conditional is in the code. From my tests, this seems to only apply for the case of the empty "if" block. NetBeans provides "hints" (those yellow underlined warnings that are also marked in the right margin of the source code editor) for several types of empty statements, but -Xlint:empty seems to only flag the empty "if" statements. I included the others that NetBeans flags along with the one -Xlint:empty flags in the next source code sample.

/**
* This method demonstrates how javac's -Xlint:empty works. Note that javac's
* -Xlint:empty will only flag the empty statement involved in the "if" block,
* but does not flag the empty statements associated with the do-while loop,
* the while loop, the for loop, or the if-else. NetBeans does flag these if
* the appropriate "Hints" are turned on.
*/
private static void demonstrateEmptyWarning()
{
int[] integers = {1, 2, 3, 4, 5};
if (integers.length != 5);
out.println("Not five?");

if (integers.length == 5)
out.println("Five!");
else;
out.println("Not Five!");

do;
while (integers.length > 0);

for (int integer : integers);
out.println("Another integer found!");

int counter = 0;
while (counter < 5);

out.println("Extra semicolons.");;;;
}
The code above is filled with problematic placement of semicolons that almost certainly are not what the developer wanted. This code will compile, but the developer is warned of these suspicious situations if -Xlint, -Xlint:all, or -Xlint:empty is used with javac. The warning messages that are printed in the otherwise successful compilation are shown next.

src\vaani\examples\Main.java:197: warning: [empty] empty statement after if
if (integers.length != 5);
^

Only the empty "if" statement clause is flagged; the others are not reported by -Xlint:empty.
-Xlint:fallthrough
A tempting but controversial convenience Java provides is the ability to "fallthrough" common expressions in a switch statement to apply the same logic to multiple integral values with one piece of code. If all of the integral values with the shared functionality are empty except the final one that actually performs the functionality and provides a break, the -Xlint:fallthrough won't be activated. However, if some of the case expressions do perform their own logic in addition to the common fallthrough logic, this warning is produced. An examples that demonstrates this is shown next.


/**
* Cause -Xlint:fallthrough to print warning about use of switch/case
* fallthrough.
*/
private static void demonstrateFallthroughWarning()
{
out.print("Wilma's favorite color is ");
out.print(wilma.getFavoriteColor() + ", which is ");

// check to see if 'artistic' primary color
// NOTE: This one will not lead to -Xlint:fallthrough flagging a warning
// because no functionality is included in any of the case statements
// that don't have their own break.
switch (wilma.getFavoriteColor())
{
case BLUE:
case YELLOW:
case RED:
out.print("a primary color for artistic endeavors");
break;
case BLACK:
case BROWN:
case CORAL:
case EGGSHELL:
case GREEN:
case MAUVE:
case ORANGE:
case PINK:
case PURPLE:
case TAN:
case WHITE:
default:
out.print("NOT a primary artistic color");
}
out.print(" and is ");
// check to see if 'additive' primary color
// NOTE: This switch WILL lead to -Xlint:fallthrough emitting a warning
// because there is some functionality being performed in a case
// expression that does not have its own break statement.
switch (wilma.getFavoriteColor())
{
case BLUE:
case GREEN:
out.println("(it's not easy being green!) ");
case RED:
out.println("a primary color for additive endeavors.");
break;
case BLACK:
case BROWN:
case CORAL:
case EGGSHELL:
case MAUVE:
case ORANGE:
case PINK:
case PURPLE:
case TAN:
case YELLOW:
case WHITE:
default:
out.println("NOT a primary additive color.");
}
}
The above code example intentionally shows both cases (pun intended) of the switch/case that will and will not lead to a warning message thanks to -Xlint:fallthrough. The output, with only one warning, is shown next.


src\vaani\examples\Main.java:95: warning: [fallthrough] possible fall-through into case case RED:
                                 ^

The case that got flagged was the RED case following the GREEN case that did some logic of its own before falling through to the RED logic.
-Xlint:finally
More than one person has warned, "Don't return in a finally clause." In fact, "Java's return doesn't always" is in The Java Hall of Shame. A Java developer can be warned about this nefarious situation by using -Xlint, -Xlint:all, or -Xlint:finally. A piece of source code demonstrating how this warning could be generated is shown next.

/**
* Demonstrate -Xlint:finally generating warning message when a {@code finally}
* block cannot end normally.
*/
private static void demonstrateFinallyWarning()
{
try
{
final double quotient = divideIntegersForDoubleQuotient(10, 0);
out.println("The quotient is " + quotient);
}
catch (RuntimeException uncheckedException)
{
out.println("Caught the exception: " + uncheckedException.toString());
}
}


/**
* Divide the provided divisor into the provided dividend and return the
* resulting quotient. No checks are made to ensure that divisor is not zero.
*
* @param dividend Integer to be divided.
* @param divisor Integer by which dividend will be divided.
* @return Quotient of division of dividend by divisor.
*/
private static double divideIntegersForDoubleQuotient(final int dividend, final int divisor)
{
double quotient = 0.0;
try
{
if (divisor == 0)
{
throw new ArithmeticException(
"Division by zero not allowed: cannot perform " + dividend + "/" + divisor);
}
// This would not have led to Xlint:divzero warning if we got here
// with a literal zero divisor because Infinity would have simply been
// returned rather than implicit throwing of ArithmeticException.
quotient = (double) dividend / divisor;
}
finally
{
return quotient;
}
}


The above is flawed and likely isn't what the developer intended. The relevant warning javac provides when Xlint is enabled is shown next.

src\vaani\examples\Main.java:159: warning: [finally] finally clause cannot complete normally
}
^

-Xlint:overrides
The -Xlint:overrides option does not replace the @Overrides annotation. The latter is an error rather than a warning anyway. Instead, -Xlint:overrides indicates when a much less obvious situation has occurred. Two Java classes are shown here to illustrate how this warning might occur. The first class is the base class and the second class extends that base class, tries to override one of the base class's methods with inclusion of an @Overrides annotation. Like all code in my examples in this post, this code does compile.
BaseClass.java


package vaani.examples;

import java.util.ArrayList;
import java.util.List;

/**
* Simple class intended to help demonstrate -Xlint:overrides by providing a
* method that won't be overridden quite the same by its child.
*/
public class BaseClass
{
protected List<String> names = new ArrayList<String>();

public BaseClass() {}

public void addNames(final String[] newNames)
{
for (final String name : newNames)
{
names.add(name);
}
}
}

ChildClass.java

\
package vaani.examples;

/**
* Simple class intended to help demonstrate -Xlint:overrides by "sort of"
* overriding a method defined in its parent.
*/
public class ChildClass extends BaseClass
{
@Override
public void addNames(final String... newNames)
{
for (final String name : newNames)
{
this.names.add(name);
}
}
}
Here is the warning javac provides when the appropriate -Xlint flag is used.

src\vaani\examples\ChildClass.java:10: warning: addNames(java.lang.String...) in dustin.examples.ChildClass overrides addNames(java.lang.String[]) in dustin.examples.BaseClass; overridden method has no '...'
public void addNames(final String... newNames)
^

-Xlint:path
The -Xlint:path is one of my favorites. I like it so much, in fact, that I have blogged on it specifically. As I stated in that post, this is particularly handy in identifying assumed classpath locations that don't really exist. This knowledge can help in all kinds of class loader issues. The option is not limited to classpaths, but that is where I use it most.
There are a couple interesting notes about this particular option. First, this was one I was unable to generate when building with Ant because Ant automatically detects non-existent paths as well and doesn't apply them (therefore not giving -Xlint:path a chance to be the hero).
The type of Ant declaration I often use when compiling my Java code is shown next. It specifies -Xlint for all javac warnings in the compilerarg element nested with the javac element.

<target name="compile"
description="Compile the Java code."
depends="-init">
<javac srcdir="${src.dir}"
destdir="${classes.dir}"
classpathref="classpath"
debug="${javac.debug}"
includeantruntime="false">
<compilerarg value="-Xlint"/>
</javac>
</target>


When I build my sample application using Ant and the target shown above, I do not see the path-oriented warning. If I turn up the verbosity during the Ant build, I can detect why when it reports this message: "dropping C:\noSuchDirectory from path as it doesn't exist"
When I build my final example with javac on the command line, there are 13 warnings covering the ten Xlint categories displayed. When I build it using Ant and the target above, there are only 12 warnings displayed and all but the -Xlint:path warning are listed. Here is what the output from -Xlint:path does look like when javac is run from the command line:

warning: [path] bad path element "C:\noSuchDirectory": no such file or directory


The second interesting observation about -Xlint:path is that it's not a source code warning like the others covered here, but is instead more a warning about how javac itself is being applied to the source code. Given that, there's no source code to see here. Let's move on.
-Xlint:serial
Josh Bloch, in Effective Java, discusses the importance of generating a serialVersionUID for classes that are marked as Serializable. Indeed, the Javadoc for Serializable also cover the importance of this. The -Xlint:serial flag will warn a developer when a Serializable class does not have an explicit serialVersionUID. It's time to look at the previously mentioned Person class (discussed in conjunction with -Xlint:deprecation), which is Serializable, but does not have an explicit serialVersionUID declared.


package vaani.examples;

import java.io.Serializable;

/**
* Person class that intentionally has problems that will be flagged as warnings
* by javac with -X non-standard options.
*/
public final class Person implements Serializable
{
// no serialVersionUID should demonstrate -Xlint:serial

private final String lastName;

private final String firstName;

private final Gender gender;

private final Color favoriteColor;

public Person(
final String newLastName,
final String newFirstName,
final Gender newGender,
final Color newFavoriteColor)
{
this.lastName = newLastName;
this.firstName = newFirstName;
this.gender = newGender;
this.favoriteColor = newFavoriteColor;
}

public String getLastName()
{
return this.lastName;
}

public String getFirstName()
{
return this.firstName;
}

public String getFullName()
{
return this.firstName + " " + this.lastName;
}

/**
* Provide the person's full name.
*
* @return Full name of this person.
* @deprecated Use getFullName() instead.
*/
@Deprecated
public String getName()
{
return this.firstName + " " + this.lastName;
}

public Gender getGender()
{
return this.gender;
}

public Color getFavoriteColor()
{
return this.favoriteColor;
}


/**
* NetBeans-generated equals(Object) method checks for equality of provided
* object to me.
*
* @param obj Object to be compared to me for equality.
* @return {@code true} if the provided object and I are considered equal.
*/
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final Person other = (Person) obj;
if ((this.lastName == null) ? (other.lastName != null) : !this.lastName.equals(other.lastName))
{
return false;
}
if ((this.firstName == null) ? (other.firstName != null) : !this.firstName.equals(other.firstName))
{
return false;
}
if (this.gender != other.gender)
{
return false;
}
if (this.favoriteColor != other.favoriteColor)
{
return false;
}
return true;
}


/**
* NetBeans-generated hashCode() method.
*
* @return Hash code for this instance.
*/
@Override
public int hashCode()
{
int hash = 7;
hash = 59 * hash + (this.lastName != null ? this.lastName.hashCode() : 0);
hash = 59 * hash + (this.firstName != null ? this.firstName.hashCode() : 0);
hash = 59 * hash + (this.gender != null ? this.gender.hashCode() : 0);
hash = 59 * hash + (this.favoriteColor != null ? this.favoriteColor.hashCode() : 0);
return hash;
}


@Override
public String toString()
{
return getFullName();
}
}


Here is what javac tells me about this when I have -Xlint, -Xlint:all, or -Xlint:serial specified.

src\dustin\examples\Person.java:9: warning: [serial] serializable class dustin.examples.Person has no definition of serialVersionUID
public final class Person implements Serializable

            ^

-Xlint:unchecked
We've finally arrived at the tenth -Xlint option. This one is covered last because "U" falls so late in the English alphabet, but it's arguably appropriate to cover it last anyway because it's one of the ones most Java developers probably see most often. This -Xlint:unchecked and the previously covered -Xlint:deprecation are the only two of the ten covered here that are warned about even when -Xlint is explicitly stated to warn about "none." Because it's so common, there are numerous code samples that demonstrate it. One simple one is shown here.

/**
* Demonstrate the commonly seen -Xlint:unchecked in action.
*
* @return Set of Person objects.
*/
private static Set<person> demonstrateUncheckedWarning()
{
final Set people = new HashSet();
people.add(fred);
people.add(wilma);
people.add(barney);
return people;
}

I could have declared the Set interface and its HashSet implementation above to be specifically of type Person, but I failed to do so. This leads to four warnings as shown next.

src\dustin\examples\Main.java:243: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.Set
people.add(fred);
^
src\dustin\examples\Main.java:244: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.Set
people.add(wilma);
^
src\dustin\examples\Main.java:245: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.Set
people.add(barney);
^
src\dustin\examples\Main.java:246: warning: [unchecked] unchecked conversion
found : java.util.Set
required: java.util.Set
return people;
^

The numerous warnings here are how my example got 13 total warnings for ten Xlint categories.

Other Noteworthy Items
This post is already pretty long, so I'm only going to briefly mention a last few items of interest. First, not only can one go without using -Xlint at all when using javac or use -Xlint:none to explicitly not use -Xlint, but one has even more granular control on what is not printed. This is available by using a minus sign (-) in front of a particular Xlint option to specify not to warn about it. For example, a developer who doesn't care about not having a serialVersionUID could specify -Xlint:-serial to explicitly tell the javac compiler to not warn about absence of a serialVersionUID in a Serializable class.
Another way to limit the printing of these Xlint-based warnings is (at least in some cases) the availability of the @SuppressWarnings annotation to state which warnings should be ignored. These annotations are placed directly in the source code, but will keep Xlint from reporting the warning. Casper Bang provides nice coverage of the use of this annotation in his post @SuppressWarnings values. Alex Miller has provided a nice summary of @SuppressWarnings options as well.
I mentioned briefly that NetBeans covers several more "empty" conditions than does -Xlint. This tends to be true of many other warnings as well. NetBeans and the other major Java IDEs tend to warn about more types of suspicious behavior than does -Xlint.

The Rest of the Code
I already included the complete source code for three classes above (Person.java, BaseClass.java, and ChildClass.java). Here I include source code for the Main.java that had many of the examples that led to Xlint complaining along with the source code for the two simple enums Gender and Color.

 

Source – Inspired by actual events