The JavaOne schedule builder has been improved since last year, and it is now easier to resolve conflicts. This is much appreciated. However, the builder should have been written in Java or AJAX to limit the time required to reload the page after adding a session.
Anyways, I just finished building my schedule, and I found the print option to be somewhat lacking. However, I also mailed the schedule to myself and that version did not include all the headers. After printing the mail in two-pages-per-sheet mode, I noticed that I could fit it in my trusted moleskine® notebook:
I apologize about the quality; my real camera was stolen on my way to FOSDEM 2007. This picture is from my Razr V3.
Come to our BOF sessions at JavaOne and hear more about the Java programming language and the Java technology tools (including javac).
Alex and I are on stage at EclipseCon 2007 waiting to give our presentation, unfortunately this means that we are missing Scott Adams who we can hear from the conference room next to ours.
So if you're interested in hearing our talk on Java SE 7 language features, now would be a good time to head down to Santa Clara Convention Center. We start at 10:10am.
The short answer is that HotSpot is not targeted to javac code but some static transformation can adversely affect the performance of your application. I'll give some more details below.
Damon also mentioned that there had been some fuss about a VM crash caused by some code generated by jikes. I know that all the HotSpot engineers treat VM crashes with utmost urgency and I checked with Ken Russell. Ken remembers one particular crash where jikes used the invokeinterface bytecode to call methods declared in java.lang.Object. This crash was treated with high priority and has since been fixed.
HotSpot is just a piece of software and may contain bugs but that does not mean javac is getting a better deal. However, there are certain factors which can play a role in how good a job HotSpot can do on your application.
Some of the industry benchmarks are based on the combination of compiler and JVM so if HotSpot seems biased towards javac, that may be the reason but not intentional.
On the other hand, many static optimizers will automatically inline method calls. The fundamental problem with inlining method calls is that if the inlined method was never called by method into which it was inlined it will just make the resulting method bigger (and perhaps prevent it from being inlined in other methods). So although a static optimizer think it is optimizing it has no data about how the program behaves at runtime and may make mistakes.
This is a fundamental problem that will make your programs run slower on HotSpot. The name HotSpot comes from the VM's ability to recognize hotspots in the program based on statistics collected while the program is running. By using this data, HotSpot can generally make better decisions than a static optimizer.
Besides hurting HotSpots ability to inline based on live data, big
methods resulting from premature inlining can have other negative
effects on performance. HotSpot will compile hot
methods
to native machine code. This code is sensitive to CPU level
optimizations such as code caches and branch prediction. I don't know
if this is a real life problem.
I checked with Ken and Ross Knippel to see if there could be other problems and they mentioned that obfuscators sometimes makes some very radical transformations of the control flow of your application. This can cause problems for HotSpots ability to detect loops and optimize them. A similar problem could occur if the compiler generated code that looked very different from what javac and similar compilers generate. However, in Mustang, HotSpot will apply a technique called loop rotation to properly place a loop exit that is testing an induction variable. Ross provided this example:
int i = 0;
while (true) {
stmt1;
i++;
if (i >= n) break;
stmt2;
}
is transformed into
int i = 0;
stmt1;
i++;
if (i < n) {
do {
stmt2;
stmt1;
i++;
} while (i < n)
}

Joe has posted about JSR 269 events on his blog. I may join him at his booth slot on Tuesday.
Imagine writing s StarOffice macro in Java
So while this is good style:
/** * ... * @throws java.lang.RuntimeException if an unrecoverable error * occurred in a user supplied component. The cause will be the * error in user code. */
This is not:
void run() throws RuntimeException;
So how can I reliably find all unchecked exceptions? Very easily if I use an annotation processor. I used this annotation processor:
@SupportedAnnotationTypes("*") @SupportedOptions("summary") public class FindRuntimeException extends AbstractProcessor { // For summary of unchecked exceptions used in throws clauses final Set<TypeMirror> uncheckedExceptions = new LinkedHashSet<TypeMirror>(); public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) { // Get various utility classes final Elements elements = processingEnv.getElementUtils(); final Types types = processingEnv.getTypeUtils(); final Messager log = processingEnv.getMessager(); // Get the types (type mirrors) of RuntimeException and Error final TypeMirror runtimeException = elements.getTypeElement("java.lang.RuntimeException").asType(); final TypeMirror error = elements.getTypeElement("java.lang.Error").asType(); // Scanner for traversing the structure of a class, interface, etc. ElementScanner6<Void,Void> scan = new ElementScanner6<Void,Void>() { @Override public Void visitExecutable(ExecutableElement e, Void p) { // Executable means method or constructor, this method is called for // every method or constructor. So we just have to look at the throws // declaration... for (TypeMirror t :e.getThrownTypes()) // ...and see if any of the thrown types are subtypes of // RuntimeException or Error. if (types.isSubtype(t, runtimeException) || types.isSubtype(t, error)) { uncheckedExceptions.add(t); // print a warning so you can use your favorite editor to jump // to the problematic method log.printMessage(WARNING, "Throwing unchecked exception " + t, e); } return null; } }; // examine all the classes provided on the command line for (TypeElement e : roundEnvironment.getSpecifiedTypeElements()) scan.scan(e); // print a summary of found unchecked exceptions if (roundEnvironment.processingOver() && processingEnv.getOptions().containsKey("summary")) { System.out.println("Summary of unchecked exceptions found in throws clauses:"); for (TypeMirror t : uncheckedExceptions) System.out.println("\t" + t); } return true; } }
UPDATE: I have updated the code with comments and colors (using htmlize.el by Hrvoje Niksic)
Then I compiled the annotation processor:
javac -classpath /usr/java/jdk1.6.0/lib/tools.jar FindRuntimeException.java
You need a fairly recent Mustang snapshot to compile this. Also, from b74 (Thanks Kelly!), you won't have to put tools.jar on the classpath anymore. Then run the annotation processor:
javac -Asummary -proc:only -processor FindRuntimeException src/share/classes/javax/tools/*.java
Enjoy...
pack200 -r -G debug.jar
This will strip all debug information from the jar file. Now this is a round-about way of doing it and probably not the fastest way. However, it works in a plain Sun JDK.
Tomorrow I'll try to sneak into the NetBeans day if I can find it.
Dijkstra did understand what he was talking about.
Dijkstra was urging the community to move forward and work with higher abstractions.
Dijkstra points out that our intellectual powers are limited in a fashion that should make us strive to shorten the conceptual gap between the static program and the dynamic process.
A modern example of this conceptual gap is found when adding an element to a collection and extracting it in the Java™ Programming Language before the advent of generic types:
List strings = new ArrayList(); // list of strings
strings.add("Hello");
...
String s = (String)strings.get(0);
Notice how the programmer is required to bridge a conceptual gap by adding comments and casts that aren't enforced by the compiler as it is with generic types:
List<String> strings = new ArrayList<String>();
strings.add("Hello");
...
String s = strings.get(0);
Also notice that the compiler will notify the developer if he makes mistakes:
Integer i = (Integer)strings.get(0); // compile-time error strings.add(1); // compile-time error
The benefits should be clear and I like to think if Dijkstra had been consulted on generics he would have said: "not having generic types should be considered harmful".
Ken Arnold doesn't understand generics and thus he suggest that generics should be considered harmful. Let's examine Ken's arguments:
My colleague told me something I misunderstood, but when I follow my wrong conclusions to the end, it doesn't make sense. Thus generics is considered harmful. And so Ken declares that you shouldn't do this:
interface Holder<T> {
T[] toArray();
}
Allow me to correct your misunderstanding. You can't do this:
class Box<T> {
T[] array = new T[10]; // compile-time error
}
You should not try to work around it:
class Box<T> {
T[] array = (T[])new Object[10]; // BAD and causes a warning
}
This is an unfortunate side-effect of erasure, the VM doesn't know what T is at runtime, so the compiler has no way to generate code that can construct an array of the right type. In the VM, all arrays must record their element type. This is because arrays should be considered harmful:
public class Test {
public static void main(String... args) {
Object[] array = new String[10];
array[0] = new Object(); // causes a run-time error, ArrayStoreException
}
}
The "intuitively correct" type rule that allows
the first assignment demonstrates that arrays
aren't statically type safe. However, they are
type safe: the VM eventually rejects the problematic assignment.
If you replace arrays with the generic ArrayList, you get this program:
import java.util.*;
public class Test {
public static void main(String... args) {
List<Object> array = new ArrayList<String>(10); // compile-time error
array.add(0, new Object());
}
}
So Ken and others should consider arrays harmful, not generics.
Ken also says that because he and David can't understand the declaration of Enum then it must be evil.
Let's look at Enum, it's not that complicated:
class Enum<E extends Enum<E>> { ... }
This is called an F-bound, I'm not exactly sure what the F means but think of it as function bounds. The bound on the type variable is a function (F) of the type variable. Yes, I know that probably didn't help your understanding. Hold on, here goes...
Since Enum is a special implementation class used for the new enum types, let's look at Comparable instead. The definition of Collections.sort looks like this:
public static <T extends Comparable<? super T>> void sort(List<T> list)
T should be a type which implements Comparable of a supertype of T. In other words: T must be comparable to it self (or a supertype of itself). This is a simple recursive definition.
So how do you validate that a given type meets the criteria (is within the bounds of T). It's simple: substitute T for the type and check if the statement is true. For example, Integer implements Comparable<Integer>, so the question is does
Integer extend Comparable<? super Integer>
The answer is yes. Integer implements Comparable<Integer> which is a subtype of Comparable<? super Integer>. Piece of cake.
There are still some minor issues that must be ironed out before it goes in to the weekly Mustang drops:
javax.tools.JavaCompilerTool.run(java.io.Writer, javax.tools.JavaFileObject...)
should be an object with more detail than a mere int.
Any comments regarding these issues or other issues are welcome and should be addressed to the expert group.
I really enjoy meeting our customers at JavaOne and was pleased to see how popular apt has become. There was a lot of sessions on apt and a lot of interest in what we're doing in the tools area (javac and apt).
In the following days I'll try to post some more info on the new features we're planning in Mustang. In the meantime, here are the slides from Joe Darcy's and my BOF on "Generic Do's and Don'ts". Hopefully, we can elaborate more on these ideas in the future.