Add java11-features module: runnable demos and captured output for the ankurm.com java11-features article
This commit is contained in:
@@ -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`:
|
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
|
- `java8-features/` — see its README
|
||||||
|
- `java11-features/` — see its README
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -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]
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
Executable
+24
@@ -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
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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() + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user