Dustin's Pages

Thursday, October 28, 2010

It is important in many careers to be able to deal constructively with various forms of criticism. This is evidenced by all the posts and articles on the subject such as Are You Too Sensitive for Your Career, How to Accept Criticism While at Work, Ten Ideas How to Accept Criticism at Work, and Some Helpful Tips in Accepting Criticism. Although the skill of dealing with criticism effectively is useful for any career, it is particularly useful in software development. It is obvious that people working in industries such as retail, customer service, press, and entertainment must be able to deal with regular and sometimes heavy criticism. In this post I look at why the ability to effectively handle criticism can be just as important in software development as in any of these other industries. I only peripherally touch on what it means to "effectively handle criticism" because this is covered by numerous other articles and posts such as the ones previously referenced.

Code Reviews
I have long felt that writing source code is similar to writing prose. One of these similarities is that the author of code can feel a deep affection for what he or she writes that rivals what prose authors can feel about their work. This can make it difficult to hear others criticize that work. It is in many ways similar to an editor editing prose. In both cases, the author must be willing to listen to the criticism and, when the criticism is weighed and followed as appropriate, the product is better for it. The software developer, like the edited author, must be willing to hear that his or her work is not perfect and, hopefully in rare cases, may be severely flawed. For many software developers, this vehicle of criticism (the code review) is a regular part of the job.

Opinions and Subjectivity
Just as the prose editing process can be challenging due to the subjectivity involved in what makes for strong or interesting reading, much of what makes code "good" or even "beautiful" is in the eye of the beholder. It is sometimes even impossible to get two developers to agree on what is "simple" (see the excellent post Simplicity is Complicated). Because there is often more than one way to do something "correctly," the difference in options can become very subjective. This means that no matter how well a developer thinks he or she has done on a particular job, others can and will think that it could have been done better with their preferred approach. Software developers need to be confident, but this confidence can sometimes move into something else that leads to foisting opinions onto others. This is most readily seen in blog posts and even more so in feedback comments on blog posts. I typically dismiss "anonymous" comments or comments with no substance, but a fact-backed comment can be insightful, even if it disagrees with my thinking.

In general, we in the software development community are an opinionated bunch and we're not afraid to "share" those opinions with others even when they didn't ask for them.

Not Invented Here Syndrome
When talking about Not Invented Here (NIH) syndrome, the focus is often on how this leads to unnecessary new design, implementation, and testing of functionality that is already available and could be reused. However, another negative side of NIH can occur when the functionality is reimplemented before the original software's author has even "moved on" to something else. Often, NIH syndrome occurs in relation to third-party software or at least software written by other teams. When it is being reimplemented on the same team, this can become a form of criticism for the original author. There are implications that the original work was not good enough. Often, of course, this is not the case. There are many causes of NIH with only a small number of them being due to the original being truly insufficient for needs. Often, NIH is a result of a developer's desire to "write code" rather than "use code" or a developer's perception that it's easier to write something from scratch than to try and learn how to use something already in place. This can really get out of hand: I've seen pieces of functionality completely or almost completely re-written by each and every developer that touches that area of code. See In Defense of Not-Invented-Here-Syndrome for a discussion of situations in which NIH is not necessarily a bad thing.

Early Project/Product Termination
Most successful software developers that I know are enthusiastic about software and enjoy building things. They invest so much time, energy, and effort into their work that it often becomes extremely important to see it through to completion and deployment. Given this, it can be crushing when the project is terminated early or does not reach completion and delivery. It can be very difficult to feel motivated and to move onto another project or another product when the last one ends this way. This can be interpreted as criticism when the product or project is terminated prematurely, especially if the developer feels his or her work was part of the reason for it.

Delivered Product Reviews
Even when a software developer is fortunate enough to see their product go to market, the opportunity for receiving criticism is not past. In fact, it may only be beginning at this point. Customers can be fickle and can be demanding. Even products that start fast can quickly lose popularity. Reviews can be brutal, even when not deserved.

Blogs, Articles, Books, and Presentations
Software developers who write blogs, books, and articles and give presentations also open themselves up to potential (even likely) criticism that can be very public. This may be one explanation for why more developers don't do these things.

Conclusion
There are numerous opportunities for a software developer to be directly and indirectly criticized. There is significant room in software development for opinions and subjectivity and this makes it even easier for developers to be critical of each other, even when nothing wrong has been done. These can be constructive or destructive forms of criticism. I don't think anyone really likes to receive criticism, but developers who know how to handle it appropriately are more likely to be happy and successful.

===== HASHMAP =====
java.util.HashMap is Serializable.
java.util.HashMap$KeySet is NOT Serializable.
java.util.HashMap$KeyIterator is NOT Serializable.
java.util.HashMap$Values is NOT Serializable.
java.util.HashMap$Entry is NOT Serializable.
===== LINKEDHASHMAP =====
java.util.LinkedHashMap is Serializable.
java.util.HashMap$KeySet is NOT Serializable.
java.util.LinkedHashMap$KeyIterator is NOT Serializable.
java.util.HashMap$Values is NOT Serializable.
java.util.LinkedHashMap$Entry is NOT Serializable.
===== CONCURRENTHASHMAP =====
java.util.concurrent.ConcurrentHashMap is Serializable.
java.util.concurrent.ConcurrentHashMap$KeySet is NOT Serializable.
java.util.concurrent.ConcurrentHashMap$KeyIterator is NOT Serializable.
java.util.concurrent.ConcurrentHashMap$Values is NOT Serializable.
java.util.concurrent.ConcurrentHashMap$WriteThroughEntry is Serializable.
===== WEAKHASHMAP =====
java.util.WeakHashMap is NOT Serializable.
java.util.WeakHashMap$KeySet is NOT Serializable.
java.util.WeakHashMap$KeyIterator is NOT Serializable.
java.util.WeakHashMap$Values is NOT Serializable.
java.util.WeakHashMap$Entry is NOT Serializable.
===== TREEMAP =====
java.util.TreeMap is Serializable.
java.util.TreeMap$KeySet is NOT Serializable.
java.util.TreeMap$KeyIterator is NOT Serializable.
java.util.TreeMap$Values is NOT Serializable.
java.util.TreeMap$Entry is NOT Serializable.
===== HASHTABLE =====
java.util.Hashtable is Serializable.
java.util.Collections$SynchronizedSet is Serializable.
java.util.Hashtable$Enumerator is NOT Serializable.
java.util.Collections$SynchronizedCollection is Serializable.
java.util.Hashtable$Entry is NOT Serializable.
===== ENUMMAP =====
java.util.EnumMap is Serializable.
java.util.EnumMap$KeySet is NOT Serializable.
java.util.EnumMap$KeyIterator is NOT Serializable.
java.util.EnumMap$Values is NOT Serializable.
java.util.EnumMap$EntryIterator is NOT Serializable.

The output shown above leads to several interesting observations. First, and most importantly from this post's perspective, is the fact that most (all but WeakHashMap) of the Map implementations are themselves Serializable, but most of them (all but Hashtable) have nested classes (for keyset, values, and entryset) that are NOT Serializable.

There are several approaches that can be used if the data from one of these classes nested within Map need to be distributed. The previously referenced bug reports provide an obvious "work around." One can copy the returned key set into its own new (and Serializable) Set:

Copy the values of the Set returned by keySet(), entrySet() or values() into a new HashSet or TreeSet object: Set obj = new HashSet(myMap.keySet());

This blog post has attempted to demonstrate that Serializable cannot be taken for granted. This is particularly true when dealing with nested classes in Map implementations.

Friday, October 22, 2010

Most Java developers are somewhat familiar with Java stack traces and how to read and analyze stack traces. However, for beginning Java developers, there are some areas of stack traces that might be a little confusing. In this post, I look at some tips for reading Java stack traces and responding appropriately based on what the stack trace reports.

1. Stack Traces Are Not Just for Errors and Exceptions

A common misconception among new Java developers and among people not familiar with Java is that stack traces indicate thrown exceptions. While stack traces are commonly associated with encountered exceptions, a Java developer can access a stack trace at any time with no exception required. One way to do this is to call Thread.currentThread().getStackTrace() to access an array of StackTraceElements. I demonstrated this previously in my post The Surprisingly Simple StackTraceElement. It can be useful to access a stack trace even outside of an exceptional situation to understand how code flows. The StackTraceElement is also useful because it allows for granular access to pieces of the stack trace.

Another non-error stack trace usage is related to Java's ability to provide details about a running process when prompted from the command-line. This is described in more detail in a later section of this post.

2. Stack Trace is Presented from Latest to Earliest

One of the most important concepts of correctly understanding a stack trace is to recognize that it lists the execution path in reverse chronological order from most recent operation to earliest operation. In many ways, analyzing a stack trace correctly is like analyzing compiler errors correctly: order matters. With the compiler errors, it is generally best to analyze the first compiler error because that often causes subsequent compiler errors. Similarly, with a stack trace, it's often most useful to start with the most recent operation and work backwards as necessary up the stack trace to see how that condition was reached. For some exceptions, like some NullPointerExceptions, analysis of the line on which the exception occurred can be all that is needed to understand what went wrong.

3. Understand Chained Exceptions

Another important observation is that stack traces that do indicate exceptions often include chained exceptions. This is important to understand because it is often the case that one of the fundamental exceptions underlying the last encountered exception is the real culprit that must be appropriately addressed. Just as addressing the last compiler error reported before addressing the first reported error rarely is a good idea, it is similarly important to analyze the underlying exception. This chained exception facility was a welcome addition to Java 1.4 because it has allowed Java developers to more easily determine the real underlying cause of various exceptions. Often the most important exception to pay attention to in a long list of chained exceptions is the first one that occurred (typically listed at the very bottom of a lengthy stack trace and often preceded by "Caused by" notation).

4. Compile with Debug Turned On

When stack traces are being used to determine why an exception occurred or what the code flow was, it can be very useful to have access to the line numbers of each executed step covered by the stack trace. By default in Oracle's Java SE 6 javac, line numbers and source file names are included in stack traces. It is easy to make disable the printing of this information by setting javac's -g:none option, but this is not typically a good idea during development. Most build tools also make it easy to turn on debugging and control the debugging level. Ant, for example, provides the debug attribute for the javac task that can be set to true to turn debugging on.

5. Logging and Handling Exception Stack Traces

Because Java stack traces are so often associated with exceptions, it is useful to know how to report these properly. Fortunately, two of the most popular Java logging frameworks, java.util.logging and log4j, provide convenient methods for logging exceptions that will handle the stack trace information automatically. For example, java.util.logging provides an overloaded version of Logger.log that accepts a Throwable and log4j provides several overloaded methods on its Logger class that allow Throwables to be logged with a normal log message.

It is sometimes necessary or at least useful to access a stack trace in code situations other than logging. One way of doing this is to use the Throwable.getStackTrace() that returns an array of StackTraceElements. Another approach is to use one of the overloaded versions of Throwable.getStackTrace() that do not simply print the stack trace to standard error. These two overloaded methods allow access to the exception's stack trace via either a PrintStream or a PrintWriter. The next two code snippets demonstrate extracting a String from a Throwable using PrintWriter and PrintStream respectively.

Java supports several approaches for accessing stack traces. Several of these are outlined in An Introduction to Java Stack Traces and I've covered a couple here already. As described in Tip #1, the stack trace of the current execution can be retrieved from the current thread. The immediately preceding tip, Tip #5, covered extracting of a stack trace from an exception/error (Throwable).

There are times when it is useful to see what the current thread and other threads are doing. Java supports this by accepting a signal and responding by displaying pertinent details. Signal handling can be a little different across platforms, so it is worth learning how to send signals from the platforms used for one's Java applications. The Sun/Oracle java launcher documentation provides significant details about its JVM signal handling in the section that describes the -Xrs option (-X indicates non-standard option). Besides explaining how to use -Xrs to turn off the JVM responding to received signals, this documentation also provides more details regarding the JVM handling of the signals SIGQUIT, SIGHUP, SIGINT, and SIGTERM.

Assuming that the -Xrs option is not used, using CTRL-BREAK in the Windows console window from which a Java application started leads to a thread dump of the current threads being displayed. This is demonstrated in the following screen snapshot of running a Java application and seeing the thread dump in Windows PowerShell.

For Linux and Unix systems, this same signal is sent differently. It can be sent with CTRL-\ (CTRL button followed by back slash) or with the command kill -QUIT pid (where 'pid' is the process ID). The jstack utility tool is also easily used to see the threads associated with a particular process (often for specified process identifier).

Java IDEs such as Eclipse and NetBeans also provide mechanisms for seeing current thread dumps and stack traces.

7. Understand Java Class/Interface Naming Conventions

When reading and analyzing a Java stack trace, it is helpful to understand the class and interface naming conventions. One source of information on these conventions is provided in the Javadoc documentation for Class.getName(). This documentation explains the naming conventions for classes, interfaces, arrays, primitives, and so forth. It states that arrays are denoted with square brace: [. It also explains that array elements are marked with various letters depending on their types: L for classes and interfaces, Z for boolean, B for byte, C for char, D for double, F for float, I for int, J for long, and S for short. Knowing what these letters represent in array representations can make it easier to read information regarding these within stack traces. As I discussed in the blog post Heap Dump and Analysis with VisualVM, these same naming conventions are also described in the JVM specification for .class file format.

The naming conventions in stack traces can be dependent on the JVM implementation, so it's worthwhile to learn what the naming conventions are for the particular JVM being used.

8. Be Cognizant of Synthetic and Bridge Methods

In many stack traces, it is fairly obvious which methods are being successively invoked by tracing through the stack trace. Sometimes, however, there can be unrecognized methods. These might be from injected aspects or might be compiler-generated methods such as synthetic and bridge methods. I discussed synthetic methods in greater detail in my blog post Java's Synthetic Methods. As I stated in that post, synthetic methods are created by the compiler and usually have, in Sun's/Oracle's JVM, names such as access$100 and access$200.

9. Dude, Where's My Stack Trace?

Stack traces can be extremely useful in debugging and understanding how an application works, but they are obviously less than effective if not readily available. As described above, some Java products (such as the logging frameworks) make logging of stack traces easier. Other products log stack traces or write out their own stack traces to product-specific directories or logs. Therefore, it's important when using a new framework, tool, library, or IDE to learn where it writes its logs and stack traces. This tip also covers other essential steps such as configuring loggers appropriately to write to the appropriate locations.

10. Magnify the Power of Stack Traces with Tooling

The majority of this post has focused on reading and manually analyzing stack traces. Tools are now available that can make use of stack traces and make use of stack traces much more efficient. Eclipse's Stacktrace Console is a good example of what a Java IDE can do to make use of stack traces easier. Stack traces can be pasted into this tool and then portions of the stack trace can be clicked on to be taken directly to that class and method. NetBeans offers similar tooling features that support easier access of stack traces to the underlying classes and methods displayed in the stack trace. Likewise, these IDEs also support generating/displaying thread dumps.

Another "tool" that is useful in conjunction with thread analysis is the powerful search engine. Although I agree that there is merit to not going right to the search engine for every problem, I have also been the beneficiary more times than I can recall of others' insight and experiences in resolving especially difficult problems. This is why I have written before that more software developers should write blogs. Search engines make it much easier to find a description of a potential fix to some nasty problems. It is often the stack trace that provides the best clues for finding the appropriate matches via search engines such as Google, Yahoo!, and Bing. Stack trace excerpts are often found in forum threads and blog posts that either directly address the issue or provide enough information to help think through what related condition might be causing the issue.

Conclusion

The humble stack trace is one of the Java developer's most powerful tools. It is especially powerful in debugging and analyzing existing software, but can even be useful in software development. In this post I have attempted to outline some simple techniques for getting the most value from these stack traces.

Monday, October 18, 2010

In this blog post, I look at the concept of Java synthetic methods. The post summarizes what a Java synthetic method is, how one can be created and identified, and the implications of Java synthetic methods on Java development.

The Java Language Specification (section 13.1) states "Any constructs introduced by the compiler that do not have a corresponding construct in the source code must be marked as synthetic, except for default constructors and the class initialization method." Further clues as to the meaning of synthetic in Java can be found in the Javadoc documentation for Member.isSynthetic(). That method's documentation states that it returns "true if and only if this member was introduced by the compiler." I like that very short definition of "synthetic": a Java construct introduced by the compiler.

The Java compiler must create synthetic methods on nested classes when their attributes specified with the private modifier are accessed by the enclosing class. The next code sample indicates this situation.

The above code compiles without incident. When javap is run against the compiled .class file, the output is as shown in the following screen snapshot.

As the above screen snapshot indicates, a synthetic method with the name access$100 has been created on the nested class NestedClass to provide its private String to the enclosing class. Note that the synthetic method is only added for the single private attribute of the NestedClass that the enclosing class accesses. If I change the enclosing class to access all private attributes of NestedClass, additional synthetic methods will be generated. The next code example demonstrates doing just this and the screen snapshot following it proves that four synthetic methods are generated in that case.

As the previous two code snippets above and the associated images show, the Java compiler introduces synthetic methods on an as-needed basis. When only one of the nested class's private attributes was accessed by the enclosing class, only one synthetic method (access$100) was created by the compiler. However, when all four private attributes of the nested class were accessed by the enclosing class, four corresponding synthetic methods were generated by the compiler (access$100, access$200, access$300, and access$400).

In all cases of an enclosing class accessing its nested class's private data, a synthetic method was created to allow that access to happen. What happens when the nested class provides an accessor for its private data that the enclosing class can use? That is demonstrated in the next code listing and in its output as shown in the next screen snapshot.

DemonstrateSyntheticMethods.java with Nested Class Public Accessor for Private Data

The above screen snapshot demonstrates that the compiler did not need to generate a synthetic method for accessing the private Date attribute in the nested class because the enclosing class accessed that attribute via the provided getDate() method. Even with getDate() provided, the compiler would have generated a synthetic method for accessing the date has the enclosing code been written to access the date attribute directly (as a property) rather than via the accessor method.

The last screen snapshot brings up another observation. As the newly added getDate() method shows in that screen snapshot, modifiers such as public are included in javap output. Because no modifier is shown for the synthetic methods created by the compiler, we know that they are package level (or package-private). In short, the compiler has created package-private methods for accessing private attributes.

The Java reflection APIs provide another approach for determining synthetic methods. The next code listing is for a Groovy script that will use the Java reflection APIs to conveniently provide details regarding the methods of the nested class shown above.

When the above Groovy script is executed against the class and nested class shown above, the output is that shown in the next screen snapshot.

The results of the Groovy script shown in the previous image verify what javap had already told us: there are four synthetic methods and one non-synthetic method defined on the nested class NestedClass. The script also tells us that the compiler-generated synthetic methods are package-private scope.

The addition of synthetic methods to the nested class at package-private scope level is not the only thing the compiler did in the above example. It also changed the scope of the nested class itself from the private setting in code to package-private in the .class file. Indeed, while the synthetic methods were only added in the case where the enclosing class accessed the private attribute, the compiler always makes the nested class package-private even if it's specified as private in the code. The good news is that this is a resulting artifact of the compilation process, meaning that code cannot be compiled as-is against the changed scope level of the nested class or its synthetic methods. Runtime is where things can get dicey.

The class, Rogue, attempts to access some of the NestedClass synthetic methods. Its source code is shown next, followed by the compiler error seen when trying to compile this Rogue source code.

Many of us can go for a long time in Java development without needing significant understanding of synthetic methods. However, there are situations when awareness of these is important. Besides security issues related to these, it is also to be aware of what they are when reading stack traces. Method names such as access$100, access$200, access$300, access$400, access$500, access$600, and access$1000 in the stack trace reflect synthetic methods generated by the compiler.

Friday, October 15, 2010

One of the most frustrating things about HTML development over the years has been dealing with browser idiosyncrasies and differences. We've been forced to litter our code with detection scripts. As we move toward HTML5, these same issues must be dealt with. Modernizr is a handy tool that reduces some of the difficulties involved in applying HTML5 features across multiple browsers. Even the main web page for Modernizr is helpful in HTML5 development because it uses its own JavaScript library to indicate which features the web browser rendering that page supports.

As the above screen snapshots indicate, Microsoft Internet Explorer 8 lags well behind the other three web browsers in terms of modern feature support. Microsoft Internet Explorer 9 is expected to reduce the gap in modern feature functionality.

As demonstrated in the above screen snapshots, Modernizr is useful in quickly ascertaining which features are supported in each browser. However, Modernizr's real power comes in applying it within web applications for simple and convenient feature detection rather than writing custom feature detection JavaScript code. Modernizr simplifies feature detection, which is generally preferable (as documented here) to user agent detection (AKA browser detection). Developers can include calls to the small Modernizr JavaScript library to reliably detect which features are available in a particular browser.

Today's announcement that IBM will collaborate on OpenJDK comes at an important time for the Java community. For years, Java developers wondered if Sun would ever open source Java. Recently, some have questioned Oracle's commitment to open source. Today's announcement may mean the most support for OpenJDK since its announcement with two major and well-funded sponsors in Oracle and IBM. It also appears to solidify Oracle's commitment to an open source Java. It is certainly in IBM's interest to have an open source Java, but it also can aid Oracle in terms of credibility in the Java community. OpenJDK offers one of those proverbial "win-win" situations for these two companies, but should benefit the rest of us "little people" as well.

The timing of this announcement was important. As the press release states, this announcement may reassure individuals and organizations who have invested significantly in Java-based applications. It may similarly reassure potential future customers. In addition, this announcement can be interpreted as a sign of how Oracle intends to fulfill its commitment to an open source Java. This is certainly a major announcement that should please most Java developers.

IBM will work with Oracle and the Java community to make OpenJDK the primary high performance open source runtime for Java. IBM will be shifting its development effort from the Apache Project Harmony to OpenJDK. ... We think this is the pragmatic choice. It became clear to us that first Sun and then Oracle were never planning to make the important test and certification tests for Java, the Java SE TCK, available to Apache. We disagreed with this choice, but it was not ours to make. So rather than continue to drive Harmony as an unofficial and uncertified Java effort, we decided to shift direction and put our efforts into OpenJDK.

The NetBeans IDE makes it easier to control which hints are enabled. This granular level of control is desirable because not every hint is created equal. Some hints, in my opinion, should always be enabled and these are the subject of this post. Other hints, may not be quite as useful for general use and some might even get in the way. I like to have only the hints that matter enabled so that I have a better chance of clearing the yellow highlighting and margin marks that indicate a warning condition. I like to have a "clean" Java source file in NetBeans so that if any significant conditions are introduced, the emergence of yellow tips me off. It is nice to disable less important (to me) hints so that this clean IDE view of the source can be maintained.

It is easy to enable Java hints in NetBeans. Select "Tools" from the title bar, then select "Options" from the drop-down menu. Choose the "Editor" option and then select the "Hints" tab. At this point, make sure that the "Language" drop-down is set to "Java" (other choices include PHP, JavaScript, and Ruby). The screen snapshot below shows how this appears, including the twenty-four categories of hints. The + sign to the left of each hints category can be clicked on to expand it and see specific hints within each category. These can then be selected to have them enabled in the IDE.

One of the categories of hints is "Standard Javac warnings." These are the warnings that I discussed in my blog post javac -Xlint Options. As I stated in that post, some of these can bring a developer's attention to some important conditions in the Java code. In particular, the support for striking out deprecated code marked with @deprecated and @Deprecated is useful in keeping new code from using deprecated methods. The next screen snapshot shows these "Standard Javac warnings."

In this post, I won't look at any of NetBeans' hints in this "Standard Javac warnings" hints category because they are covered by javac's -Xlint. Instead, I focus in this post on warnings that NetBeans hints provide that are not available via javac. Indeed, NetBeans provides some handy warnings for some very dangerous ("suspicious") conditions that I wish the standard compiler warned me about!

It is arguable which is the "most important" of the NetBeans hints, but the hint for "suspicious method call" certainly should be high on anyone's list. This hint, which falls under "Probable Bugs" hints category, warns about the dangerous (more than suspicious in my mind) situation I described in the blog post The Contains Trap in Java Collections. The following code snippet shows code that causes this hint to lead to three warnings.

With the "suspicious method call" hint enabled as a warning, NetBeans clearly flags the three occurrences of this situation in the code above as demonstrated in the next image.

As the above screen snapshot indicates, NetBeans flags the three "suspicious method calls" that occur in the code. They are highlighted with yellow underlining and with yellow marks in the right margin. The light bulb icons on the left can be clicked on to see more details and potential resolution options.

In this case, I find this condition of significant enough concern that a warning is not sufficient. NetBeans allows me to specify that this hint results in an error instead of a warning. For example, I can click on the light bulb icon and select "Configure 'Suspicious method call' Hint" option to change it. The new screen is shown next.

With the "Show As" drop-down set to "Error," NetBeans now shows this significant issue as an error in the IDE! This is shown in the next screen snapshot, which is the same as above, but with error-level markings.

Setting the "suspicious method calls" hint to appear as error rather than warning helps make it even more obvious in large code bases. Although I won't specifically show this transition for each NetBeans hint to "error" in this post, it is not surprising that many of these "indispensable" hints could arguably be set to "error" rather than "warning" for NetBeans reporting. NetBeans gives us the flexibility to select which hints we want flagged and which hints we want flagged as errors versus as warnings. One important observation is that NetBeans's treatment of a hint as an error is only for viewing and does not prevent NetBeans from building the source code successfully.

An important NetBeans hint is the "Comparing Strings using == or != hint. This hint flags the well-known issue in Java when Strings (usually mistakenly) are compared using == or != instead of .equals. The danger is increased dramatically when coupled with String instantiations using the new keyword and that's what NetBeans's "String constructor" hint catches. The next code snippet leads to these two hints being triggered. The NetBeans response to that code is shown after the code.

Another dangerous problem occurs when a constructor calls a method on the same class that might be overridden by child method. This is demonstrated in the next code snippet, but fortunately NetBeans can identify this bad behavior with the "Overridable method call in constructor" hint.

package dustin.examples;
/**
* This class is full of misbehavior to help demonstrate NetBeans hints.
*/
public class MisbehavingClass
{
/**
* This constructor does a bad thing: it calls an overridable method.
*/
public MisbehavingClass()
{
initialize();
}
protected void initialize()
{
// do some initialization
}
}

Not surprisingly, the "Probable Bugs" category of NetBeans hints has numerous hints that warn of potentially serious complications. For example, the ".equals on incompatible types" hint will be triggered by the following code snippet.

This hint is in many ways like the "suspicious method call" hint covered earlier. Both of these hints warn about cases where the fact that the API necessarily needs to accept an Object instance leaves open the possibility of passing in types that simply can never match what is expected.

I always prefer to know about code issues as early as possible in the development cycle as possible. Specifically, when possible, I'd rather know about code that's flat-out wrong at compile time rather than at runtime. NetBeans includes several hints that let me know of a problem in my code that I'd otherwise not know about until runtime. I've already covered some of these above (the "suspicious method call" and ".equals on incompatible type" hints are two such examples), but the Probable Bugs category of hints provides another particularly useful hint in the "Incompatible Cast/Incompatible instanceof" hint.

This "Class is incompatible with instance of" hint notifies the developer that the type being checked in an outer instanceof operator check is not the same type (and is not compatible with) the type being cast when the instanceof evaluates to true. This is important because the compiler does not report an error or warning in this case. Instead, the problem is not encountered until runtime when a ClassCastException is thrown when the cast attempts to an incompatible type. A code snippet that will trigger this NetBeans hint is shown next.

The above, when seen in NetBeans, looks like what is shown in the next screen snapshot.

The warning provided by NetBeans above about the cast type being incompatible with the type checked by the instanceof operator is much nicer (and much sooner) than when first encountered in runtime:

A third NetBeans hint from the Probable Bugs category is the "Incorrect Column Index in ResultSet" hint. Unlike many Java (and C/C++) based APIs, the columns in a result set accessed by column number are one-based rather than zero-based. A developer might accidentally (or out of habit) attempt to use a zero-based column index scheme. The next code sample shows how this might be done.

This NetBeans hint is also brought up for negative column indices, but that is less likely to happen then the use of a zero. This code will correctly compile, but will break at runtime with an SQLException ("Invalid column index"). Thankfully, NetBeans warns of this "probable bug" as shown in the next screen snapshot.

It is important to always provide an explicitly overridden hashCode() implementation when equals() is explicitly overridden for correct behavior. NetBeans provides a hint for this. The "Generate missing hashCode or equals" hint will warn if either of these two methods exists without the other. This is demonstrated in the following code sample and the image following the code sample shows NetBeans calling attention to the missing hashCode().

This image shows two NetBeans hints in action. The first is the "Generate missing hashCode()" hint because there is an equals(Object) method, but not a hashCode() method in this class. The second is another useful NetBeans hint that suggests that the developer should "Add @Override Annotation" to this method that overrides Object's hashCode(). I like to have this one turned on to ensure that I don't accidentally override a method that I am not intending to override. If I see this hint, I make sure it is supposed to be an overriding method and add the annotation or else change its name to not be overriding.

I've covered many aspects of NetBeans hints in this post. The ability to flag issues at compilation (or even before that) time rather than at runtime is very helpful. There are other tools that can do this, but it's really nice to have it incorporated and automatically implied directly in the IDE. Furthermore, the ability to select only those hints that are desired is useful and the ability to indicate whether a particular hint should be treated as a warning or error adds further control to the granularity of the hinting reporting. Finally, the ultimate flexibility is provided by the ability to create custom NetBeans hints, something I have not demonstrated in this post. With NetBeans 6.9 introducing so many useful hints, I'm finding reduced need of other static analysis tools.

NetBeans provides many useful hints that improve the quality, correctness, reliability, and maintainability of Java code. In this post, I've focused on some of them that I find particularly valuable. They are summarized here:

Suspicious Method Call

Comparing Strings Using == or != AND String Constructor

Overridable Method Call in Constructor

.equals Incompatible Types

Incorrect Column Index in ResultSet

Cast Incompatible with instanceof

Generate .equals or .hashCode Method

These hints are so useful (almost always a real bug) and it is so advantageous to know about them sooner (compile/pre-compile time rather than runtime), that I'd like to see these be added to Sun's/Oracle's javac's -Xlint options.

I noticed that the URLs to Oracle Technology Network (OTN) articles have changed recently. In this brief post, I list the new URLs for the articles that I have written or co-written that are published on OTN.

Tuesday, October 5, 2010

With ready accessibility to the Java SDK API documentation and Java EE API documentation online and with the convenience of IDE method name completion, it is often easy to determine a class's public exposed API. However, even with these great tools at hand, I always like to be aware of useful command-line tools to supplement these tools. Such knowledge can be particularly useful if in an environment where the online documentation or properly working IDE are not as easily available or are less desirable because of their overhead. The Sun/Oracle javac compiler supports the non-standard (and hence not guaranteed to be in other Java compiler implementations or even in future Oracle javac implementations) -Xprint option to make this easy. A side benefit of this option is for generating a textual representation of a class's API.

The javac documentation describes the -Xprint option: "Print out textual representation of specified types for debugging purposes; perform neither annotation processing nor compilation. The format of the output may change."

The output of -Xprint on a .class file looks very similar to javap's output. For example, javac -Xprint shows the following output when run against java.lang.Object:

Of course, the output above is shown with javap's default settings. The private and protected members can be displayed using javap's -private and -protected options.

One advantage of javac -Xprint, however, is that the -Xprint option can be easily used with javac if one wants to see the interface for multiple files. The javac compiler can be used as normal against the normal source code files, but with the -Xprint option specified, the interfaces will be printed out without actually compiling the code. This is demonstrated here. I add the -Xprint option to my javac compiler when compiling the examples from my last blog post on javac -Xlint and get the following output:

The output of my own classes shown above is a reminder of another nicety of javac -Xprint: it includes the Javadoc comments of the members and methods that it prints out when source code is available. This can be helpful in understanding what the parameters of the API methods are. If javac -Xprint is run directly against a .class file, it does not include the Javadoc comments; if it's run against the .java source file, it does include the Javadoc comments.

For example, if I change my directory to the installation directory of the Spring Framework, I can use the command

javac -Xprint src\org\springframework\core\Constants.java

to see the org.springframework.core.Constants class members and methods with accompanying Javadoc comments. Alternatively, I could run javac -Xprint against the compiled .class file as well (but won't see the Javadoc comments in that output) with the command

javac -cp dist\spring.jar -Xprint org.springframework.core.Constants

It is nice to be able to run javac -Xprint against compiled binaries (.class) or raw source (.java).

I usually use an IDE and the online Javadoc-based API documentation to learn new APIs or remind myself of the specifics of APIs I don't use frequently. However, every once in a while, I find it useful to be aware of the existence of javap and of javac -Xprint for providing a quick reminder of the available APIs on my own classes and on third-party classes.