At JavaOne last week, my colleague Kurchi Hazra and I (mostly Kurchi) presented this session on javac warnings. This is the latest update in our effort to clean up warnings in OpenJDK. I had talked about that in my OSCON talk earlier this year. Whereas that talk was mostly about OpenJDK (and technical debt in general, and warnings in particular), our JavaOne talk focused on explaining why warnings occur and describing various techniques for getting rid of them.
I’ve blogged about warnings cleanup previously. There is also a status page of current warnings counts in OpenJDK. Currently we’ve removed nearly half of the javac warnings in the jdk repository compared to our starting point somewhat over a year ago. This is great progress!
What was interesting about the session was the level of interest in dealing with javac warnings, not only in OpenJDK, but also in attendees’ code bases. There were over 100 attendees at the session, which was pretty good considering that it was on the afternoon of the last day of the conference, and the subject matter is very far from cutting-edge technology. The number of warnings emitted by javac is kind of a proxy for how out-of-date the source base is. I suspect there are a lot of old code bases out there that are in need of refreshing. Another indicator of the level of interest was that, during the Q&A portion of the session, it wasn’t just the audience asking questions and Kurchi and me answering them. Some conversations actually broke out among several interested audience members. So, I was pleasantly surprised at the level of interest in this topic.
I was also pleased to learn that some of the attendees had gone through the exercise of removing warnings from their own code bases. So, it’s not just the JDK that suffers from warnings! One small anecdote that an attendee related to me was that the warnings cleanup at his company exposed some team dynamics issues. Apparently the incidence of a particular kind of warning was highly correlated with a particular developer, and this led to some conflict. I was surprised by this, but not shocked. It’s easy to see how a particular, idiosyncratic coding style can lead to compiler warnings. We hadn’t run into this particular issue in the JDK warnings cleanup, but I suppose it’s something to be on the lookout for if you decide to clean up your own project.
An observation that the session reinforced for me is the number of subtle technical issues that arise because of warnings cleanup. (Most of these points are covered in more detail in the talk.) Generics certainly gives rise to the most warnings, and doing warnings cleanup has greatly improved my understanding of generics. Another language feature added in Java SE 5 was covariant overrides. Everybody forgets about this one; it leads to redundant cast warnings. “Static” warnings are issued when a static method is called through an instance. Until I saw this warning, I didn’t even know that this was a language feature! (Actually it’s more like a misfeature, since doing so gives a warning.) This wasn’t a recent change though; I think the ability to call a static method through an instance has been there since day one. Finally, “serial” warnings are issued when a Serializable class lacks a declared serialVersionUID. For purposes of serialization compatibility, one usually ought to declare a serialVersionUID on each Serializable class. But there are some subtleties here that I should probably describe in a separate post (we gloss over them in the talk as well).
In any case, the warnings cleanup effort has caused me to learn more about various obscure corners of the language. If you thought you knew Java, try cleaning up the warnings in your code base. Then you’ll really know Java.
Saying that you invoke a static method through an instance isn’t correct, since it will work even if the instance is null. The type of the reference is checked, and the static method in that type is invoked.
public class StaticTest {
public static void main(String[] args) {
A a = null;
a.print(); //Prints static in a
a = new B();
a.print(); //Prints static in a
}
}
class A {
public static void print() {
System.out.println("Static in a");
}
}
class B extends A {
public static void print() {
System.out.println("Static in b");
}
}
Fair enough, a static method isn’t invoked “through” a reference but instead is invoked using the static type of that reference, regardless of whether the reference is null or the runtime type of the object it refers to. The point of the static warning is that invoking a static via a reference is tremendously misleading. It looks like an instance method call, but it’s not.