4 minutes
Java 11
But Java is already at version 15, why talk about 11 ?! Well,…but before that, a note of caution: considering the release cycle of Java nowadays, it might be that the current version of Java at the time you are reading this is bigger than 15, it was 15 when I wrote this post!
Now, let’s continue…
Java 11 is the current (see note of caution above) LTS version, and will stay like that until Java 17 appears, which should be somewhere around the end of 2021, which is then the new LTS version (all of this hold true iff Oracle doesn’t change something in the whole release plan).
Oracle’s latest certification related to Java is for version 11, again, if they do not change anything, by the time you are reading this.
Besides, Java 11 has lots of new cool features, some of which I will be addressing in this post. Please note, that some features reached maturity with this version and were included as stable enhancements in the language.
For a complete, detailed and kinda scary compilation of all the changes check this link.
In this post I’ll be giving a short intro with examples about JEP 330 and shebang files.
Environment configuration
OS: Ubuntu 20.04.1 LTS
$ java --version
openjdk 11.0.8 2020-07-14
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.8+10)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.8+10, mixed mode)
I use sdkman to manage the versions of Java I use on my system and as such I have this:
$ whereis java
java: /etc/java /usr/share/java /home/vlad/.sdkman/candidates/java/11.0.8.hs-adpt/bin/java
$ which java
/home/vlad/.sdkman/candidates/java/current/bin/java
$ ll /home/vlad/.sdkman/candidates/java/
...
drwxr-xr-x 5 vlad vlad 4096 Sep 21 23:22 ./
drwxr-xr-x 5 vlad vlad 4096 Jun 30 17:24 ../
drwxr-xr-x 9 vlad vlad 4096 Jul 15 11:08 11.0.8.hs-adpt/
drwxr-xr-x 9 vlad vlad 4096 Jul 15 11:13 14.0.2.hs-adpt/
drwxr-xr-x 8 vlad vlad 4096 Jul 28 17:21 8.0.265.hs-adpt/
lrwxrwxrwx 1 vlad vlad 14 Sep 21 23:21 current -> 11.0.8.hs-adpt/
Now, on to some cool feature of Java 11…
Launch single-file source-code programs
As per JEP 330 we now have the possibility to launch single-file source-code programs.
Let’s code the simplest, politest Java program:
public class Greeter {
public static void main(String[] args){
System.out.println("Hello " + args[0] + "!");
}
}
Normally we would need to compile it with javac
and get that .class
file and then run it with java
to see the greeting,
but now we can just do:
$ java Greeter.java Vlad
Hello Vlad!
Now let’s turn this into a shebang file and use it like a script, a Java Script…mind the gap ;)
The main idea is to add a line (contains the path to the java binary) similar to this #!/home/vlad/.sdkman/candidates/java/11.0.8.hs-adpt/bin/java --source 11
at the beginning of a file and then the Java code after it, make the new file executable and execute it like any other sh file.
By the way, we can choose any name we want for the script file.
Content of greet
file:
#!/home/vlad/.sdkman/candidates/java/11.0.8.hs-adpt/bin/java --source 11
public class Greeter {
public static void main(String[] args){
System.out.println("Hello " + args[0] + "!");
}
}
make it executable:
$ chmod u+x greet
and execute it:
$ ./greet Vlad
Hello Vlad!
Let’s spice things up a bit and implement another more complex example: this time we want to take some text, line by line,
and display only the lines that match a given regular expression (basically a simplified version of grep
command).
Content of grep
file:
#!/home/vlad/.sdkman/candidates/java/11.0.8.hs-adpt/bin/java --source 11
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Pattern;
import java.util.stream.Stream;
public class Grep {
public static void main(String[] args) throws IOException {
// some arguments validation
if (args.length < 1 || args.length > 2) {
showUsage();
return;
}
var option = "";
var strPattern = "";
// some more arguments validation and extraction of the actual arguments
if (args.length == 1) {
if (args[0].startsWith("-")) {
showUsage();
return;
} else {
strPattern = args[0];
}
}
if (args.length == 2) {
if (args[0].startsWith("-")) {
option = args[0];
strPattern = args[1];
} else {
showUsage();
return;
}
}
// is it a case-insensitive search
var isCaseSensitive = true;
if (option.equals("-i")) {
isCaseSensitive = false;
}
var reader = new BufferedReader(new InputStreamReader(System.in));
Stream<String> lines = Stream.empty();
if (reader.ready()) {
lines = reader.lines();
}
var regex = (isCaseSensitive ? "" : "(?i)") + ".*" + strPattern + ".*";
// new Java 11 feature
// see https://cr.openjdk.java.net/~iris/se/11/latestSpec/apidiffs/java/util/regex/Pattern.html
var asMatchPredicate = Pattern.compile(regex).asMatchPredicate();
lines.filter(asMatchPredicate).forEach(System.out::println);
}
private static void showUsage() {
System.out.println("Usage: ./grep [-i] PATTERN");
}
}
Make the file executable and then you can execute it like this:
$ echo -e "aaa\nbbb\nccc" | ./grep -i CCC
ccc
$ echo -e "aaa\nbbb\nccc" | ./grep -i C{3}
ccc
$ echo -e "aaa\nbbb\nccc\n" > content
$ cat content | ./grep -i CCC
ccc
There you have it, scripting in Java has never been easier.
The examples are available in this GitHub repo.
Happy coding in Java 11!