Add java11-features module: runnable demos and captured output for the ankurm.com java11-features article

This commit is contained in:
2026-10-20 17:13:58 +00:00
parent 77c782abbf
commit 8b9447a393
19 changed files with 223 additions and 0 deletions
+1
View File
@@ -101,3 +101,4 @@ MIT licensed, see `LICENSE`.
Modules for the Java 8 / 11 / 17 / 21 feature articles, one folder each, each with `src/`, `broken/`, `output/` and `run.sh`:
- `java8-features/` — see its README
- `java11-features/` — see its README
+13
View File
@@ -0,0 +1,13 @@
# java11-features — Java 11 features with examples
Companion code for the ankurm.com article **Java 11 Features with Examples (and What Changed from Java 8)**. The explanation lives in the article; this folder holds the runnable sources and the transcripts they produced. There is no `docs/` folder: the depth is inside the article itself.
```bash
JDK8=/path/to/jdk8 JDK11=/path/to/jdk11 ./run.sh # regenerates output/*.txt
```
- `src/` compiles and runs unchanged on the JDK named in each output header.
- `broken/` fails to compile on purpose; the compiler's own message is committed in `output/`.
- `output/` is real captured output, regenerated by `run.sh`.
Tested on: Temurin 1.8.0_504 and 11.0.32.1.
+8
View File
@@ -0,0 +1,8 @@
import javax.xml.bind.JAXBContext;
/** Compiles on 8, fails on 11: JEP 320 removed the Java EE modules (java.xml.bind and friends). */
public class JaxbRemoved {
public static void main(String[] args) throws Exception {
System.out.println(JAXBContext.class.getName());
}
}
@@ -0,0 +1,9 @@
import java.util.function.BiFunction;
/** Fails to compile on purpose: you cannot mix var and explicit types in one lambda's parameters. */
public class VarWithoutLambda {
public static void main(String[] args) {
BiFunction<Integer, Integer, Integer> f = (var a, Integer b) -> a + b;
System.out.println(f.apply(1, 2));
}
}
@@ -0,0 +1,7 @@
$ javac src/StringMethods.java && java StringMethods (11.0.32.1)
trim() length : 9
strip() length : 5
isBlank(" ") : true isEmpty: false
lines() : [a, b, c]
repeat(3) : ababab
stripLeading : [x ] stripTrailing: [ x]
+3
View File
@@ -0,0 +1,3 @@
$ javac src/FilesDemo.java && java FilesDemo (11.0.32.1)
read back : one|two|three
Path.of : a/b/c.txt
@@ -0,0 +1,4 @@
$ javac src/HttpClientDemo.java && java HttpClientDemo (11.0.32.1)
sync : 200 hello from server version=HTTP_1_1
header : X-Demo=yes
async : hello from server
+3
View File
@@ -0,0 +1,3 @@
$ javac src/VarLambda.java && java VarLambda (11.0.32.1)
(var a, var b) : 5
with annotation : x-y
@@ -0,0 +1,2 @@
$ java src/SingleFile.java (11.0.32.1)
launched from source, java.version=11.0.32.1
+4
View File
@@ -0,0 +1,4 @@
$ javac src/NestMates.java && java NestMates (11.0.32.1)
nest host : NestMates
inner can read : 42
access$ methods on outer: 0
@@ -0,0 +1,20 @@
$ javac broken/JaxbRemoved.java (1.8.0_504)
(compiled cleanly)
$ javac broken/JaxbRemoved.java (11.0.32.1)
broken/JaxbRemoved.java:1: error: package javax.xml.bind does not exist
import javax.xml.bind.JAXBContext;
^
broken/JaxbRemoved.java:6: error: cannot find symbol
System.out.println(JAXBContext.class.getName());
^
symbol: class JAXBContext
location: class JaxbRemoved
2 errors
$ javac broken/VarWithoutLambda.java (11.0.32.1)
broken/VarWithoutLambda.java:6: error: invalid lambda parameter declaration
BiFunction<Integer, Integer, Integer> f = (var a, Integer b) -> a + b;
^
(cannot mix 'var' and explicitly-typed parameters)
1 error
@@ -0,0 +1,33 @@
# trim vs strip on the same string, Java 8 has no strip(); the Java 8 compile of src/StringMethods.java:
$ javac src/StringMethods.java (1.8.0_504)
src/StringMethods.java:9: error: cannot find symbol
System.out.println("strip() length : " + padded.strip().length());
^
symbol: method strip()
location: variable padded of type String
src/StringMethods.java:10: error: cannot find symbol
System.out.println("isBlank(\" \") : " + " ".isBlank() + " isEmpty: " + " ".isEmpty());
^
symbol: method isBlank()
location: class String
src/StringMethods.java:11: error: cannot find symbol
System.out.println("lines() : " + "a\nb\r\nc".lines().collect(Collectors.toList()));
^
symbol: method lines()
location: class String
src/StringMethods.java:12: error: cannot find symbol
System.out.println("repeat(3) : " + "ab".repeat(3));
^
symbol: method repeat(int)
location: class String
src/StringMethods.java:13: error: cannot find symbol
System.out.println("stripLeading : [" + " x ".stripLeading() + "] stripTrailing: [" + " x ".stripTrailing() + "]");
^
symbol: method stripLeading()
location: class String
src/StringMethods.java:13: error: cannot find symbol
System.out.println("stripLeading : [" + " x ".stripLeading() + "] stripTrailing: [" + " x ".stripTrailing() + "]");
^
symbol: method stripTrailing()
location: class String
6 errors
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
# Java 11 features: every demo compiled and run on real JDKs; regenerates output/*.txt
# JDK8=/path JDK11=/path ./run.sh
set -uo pipefail
unset JAVA_TOOL_OPTIONS
HERE="$(cd "$(dirname "$0")" && pwd)"
JDK8="${JDK8:-/opt/jdks/jdk8}"; JDK11="${JDK11:-/opt/jdks/jdk11}"
OUT="$HERE/output"; mkdir -p "$OUT"; B="$(mktemp -d)"; trap 'rm -rf "$B"' EXIT
cd "$HERE"
ver() { "$1/bin/java" -version 2>&1 | sed -n 1p | sed 's/.*"\(.*\)".*/\1/'; }
cr() { local jdk="$1" src="$2" cls="$3" o; o="$(mktemp -d -p "$B")"
echo "\$ javac $src && java $cls ($(ver "$jdk"))"
"$jdk/bin/javac" -encoding UTF-8 -d "$o" "$src" 2>&1 | grep -v '^Note:'; "$jdk/bin/java" -cp "$o" "$cls" 2>&1; }
co() { local jdk="$1" src="$2" o; o="$(mktemp -d -p "$B")"
echo "\$ javac $src ($(ver "$jdk"))"; local r; r="$("$jdk/bin/javac" -encoding UTF-8 -d "$o" "$src" 2>&1)"; if [ -n "$r" ]; then echo "$r"; else echo "(compiled cleanly)"; fi; }
cr "$JDK11" src/StringMethods.java StringMethods > "$OUT/01-string-methods.txt"
cr "$JDK11" src/FilesDemo.java FilesDemo > "$OUT/02-files.txt"
cr "$JDK11" src/HttpClientDemo.java HttpClientDemo > "$OUT/03-http-client.txt"
cr "$JDK11" src/VarLambda.java VarLambda > "$OUT/04-var-lambda.txt"
{ echo "\$ java src/SingleFile.java ($(ver "$JDK11"))"; "$JDK11/bin/java" src/SingleFile.java 2>&1; } > "$OUT/05-single-file.txt"
cr "$JDK11" src/NestMates.java NestMates > "$OUT/06-nest-mates.txt"
{ co "$JDK8" broken/JaxbRemoved.java; echo; co "$JDK11" broken/JaxbRemoved.java; echo; co "$JDK11" broken/VarWithoutLambda.java; } > "$OUT/07-compile-errors.txt"
{ echo "# the Java 8 compile of src/StringMethods.java: these String methods do not exist on 8"; co "$JDK8" src/StringMethods.java; } > "$OUT/08-string-methods-on-8.txt"
exit 0
+13
View File
@@ -0,0 +1,13 @@
import java.nio.file.*;
/** Files.readString / writeString and Path.of, new in 11. */
public class FilesDemo {
public static void main(String[] args) throws Exception {
Path p = Files.createTempFile("demo", ".txt");
Files.writeString(p, "one\ntwo\nthree");
String s = Files.readString(p);
System.out.println("read back : " + s.replace("\n", "|"));
System.out.println("Path.of : " + Path.of("a", "b", "c.txt"));
Files.delete(p);
}
}
+30
View File
@@ -0,0 +1,30 @@
import com.sun.net.httpserver.HttpServer;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.http.*;
import java.util.concurrent.CompletableFuture;
/** The standard java.net.http client (JEP 321): sync, async, against a local server so the output is stable. */
public class HttpClientDemo {
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
server.createContext("/hello", ex -> {
byte[] body = "hello from server".getBytes();
ex.getResponseHeaders().add("X-Demo", "yes");
ex.sendResponseHeaders(200, body.length);
ex.getResponseBody().write(body); ex.close();
});
server.start();
String url = "http://127.0.0.1:" + server.getAddress().getPort() + "/hello";
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create(url)).GET().build();
HttpResponse<String> r = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println("sync : " + r.statusCode() + " " + r.body() + " version=" + r.version());
System.out.println("header : X-Demo=" + r.headers().firstValue("X-Demo").orElse("?"));
CompletableFuture<String> f = client.sendAsync(req, HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body);
System.out.println("async : " + f.get());
server.stop(0);
}
}
+13
View File
@@ -0,0 +1,13 @@
import java.lang.reflect.Modifier;
/** JEP 181: nest-based access. Private members of nest mates no longer need synthetic accessor methods. */
public class NestMates {
private int secret = 42;
static class Inner { int peek(NestMates n) { return n.secret; } }
public static void main(String[] args) {
System.out.println("nest host : " + Inner.class.getNestHost().getSimpleName());
System.out.println("inner can read : " + new Inner().peek(new NestMates()));
long synthetic = java.util.Arrays.stream(NestMates.class.getDeclaredMethods()).filter(m -> m.getName().startsWith("access$")).count();
System.out.println("access$ methods on outer: " + synthetic);
}
}
+6
View File
@@ -0,0 +1,6 @@
/** Run directly with: java SingleFile.java (JEP 330, no javac step). */
public class SingleFile {
public static void main(String[] args) {
System.out.println("launched from source, java.version=" + System.getProperty("java.version"));
}
}
+15
View File
@@ -0,0 +1,15 @@
import java.util.stream.Collectors;
/** The String additions in Java 11: isBlank, lines, strip, repeat. */
public class StringMethods {
public static void main(String[] args) {
String em = String.valueOf((char) 0x2003); // EM SPACE: whitespace to strip(), not to trim()
String padded = em + " hello " + em;
System.out.println("trim() length : " + padded.trim().length());
System.out.println("strip() length : " + padded.strip().length());
System.out.println("isBlank(\" \") : " + " ".isBlank() + " isEmpty: " + " ".isEmpty());
System.out.println("lines() : " + "a\nb\r\nc".lines().collect(Collectors.toList()));
System.out.println("repeat(3) : " + "ab".repeat(3));
System.out.println("stripLeading : [" + " x ".stripLeading() + "] stripTrailing: [" + " x ".stripTrailing() + "]");
}
}
+15
View File
@@ -0,0 +1,15 @@
import java.util.function.BiFunction;
/** JEP 323: var in lambda parameters. The point is annotations, not brevity. */
public class VarLambda {
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(java.lang.annotation.ElementType.PARAMETER)
@interface NonNull {}
public static void main(String[] args) {
BiFunction<Integer, Integer, Integer> add = (var a, var b) -> a + b;
BiFunction<String, String, String> join = (@NonNull var a, @NonNull var b) -> a + "-" + b;
System.out.println("(var a, var b) : " + add.apply(2, 3));
System.out.println("with annotation : " + join.apply("x", "y"));
}
}