Running Java code from the source

Java 11 comes with a bunch changes and features (17 as listed here) one of which is JEP 330 which grants the ability of running a program from source without a separate compilation session; in other words you can now compile and run code in one go. JEP 330 describes the rules that must be followed to make use of this feature such as:

  • A single source file ought to be provided as argument, additional files are ignored.
  • The code must not have external dependencies other than java.base module.
  • The code is compiled under the unnamed module.
  • Program arguments may be supplied.
  • A compilation error stops the procedure and the program is not launched.
  • The top level class does not have to match the file name.

Decided to take this feature for a spin and time the execution. The test code is a simple hello world program consisting of two classes as seen in the following snippet

HelloWorld.java

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello Java 11");
        System.out.println("Hello " + new World());
    }
}

class World {
    public String toString() { return "World!"; }
}

Next I created two launch scripts, one that relies on the new feature and the other that compiles and runs the code the old fashioned way

runFromSource.sh

#!/usr/bin/java --source 11 HelloWorld.java

compileAndRun.sh

/usr/bin/javac HelloWorld.java
/usr/bin/java HelloWorld

Then proceeded to time them several times, the results were quite similar

$  time runFromSource.sh 
Hello Java 11
Hello World!

real    0m0.691s
user    0m1.489s
sys 0m0.106s

$ time compileAndRun.sh 
Hello Java 11
Hello World!

real    0m0.778s
user    0m1.206s
sys 0m0.109s

As you can see the time difference is not substantial however running from source skips generating intermediate class files that may be left lingering on your system if you don’t clean up afterwards. Just for kicks I wrote a similar Apache Groovy script with equivalent behavior

hello.groovy

class World {
    String toString() { 'World!' }
}

println 'Hello Groovy 11'
println "Hello ${new World()}"

Its corresponding launch shell script

runGroovy.sh

$GROOVY_HOME/bin/groovy hello.groovy

Yields a similar time as the previous two options

 time runGroovy.sh 
Hello Groovy 11
Hello World!

real    0m0.908s
user    0m1.554s
sys 0m0.154s

Of course the elephant in the room is: what about additional dependencies? As it currently stands this feature is not really groundbreaking, but (and here comes a big) IF a future release of Java adds the ability to specify additional modules that provide the much needed extra behavior THEN we have a clear winner.

Or you can simply give Apache Groovy and its @Grab feature a try, it’s been working like a charm for 10 years now.

Keep on Coding!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

ˆ Back To Top