
| Version | Year | New Language Features | Number of Classes and Interfaces |
| 1.0 | 1996 | The language itself | 200 |
| 1.1 | 1997 | Inner classes | 418 |
| 1.2 | 1998 | The strictfp modifier |
1,588 |
| 1.3 | 2000 | Nothing at all | 1,883 |
| 1.4 | 2002 | Assertions | 2,696 |
| 5.0 | 2004 | Generic classes, “for each” loop, varargs, autoboxing, metadata, enumerations, static import | 3,551 |
| 6 | 2006 | Nothing at all | 4,069 |
| 7 | 2011 | Switch with strings, diamond operator, binary literals, exception handling enhancements | 4,509 |
| 8 | 2014 | Lambda expressions, interfaces with default methods | 4,733 |
| 9 | 2017 | Modules | 6,603 |
| 10 | 2018 | var |
6,599 (!) |
| 11 | 2018 | Nothing at all | 4,910 (!!)—Java FX, JNLP, Java EE overlap, CORBA removed |
| 12 | 2019 | switch expression preview |
4,935 |
| 13 | 2019 | Text blocks preview | 4,904 |



StandardCharsets subclass of CharsetStandardCharsets.UTF_8 can be autocompleted, don't have to ponder "UTF-8" vs "UTF8" vs "UTF_8"Files.newBufferedReader(Path, Charset)Scanner(..., Charset charset) and PrintWriter(..., Charset charset)FileReader, FileWriter
openjdk-net-dev mailing list
HttpURLConnectionHttpClient client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.ALWAYS)
.build();HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("http://horstmann.com"))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandler.asString());
client.sendAsync(request, HttpResponse.BodyHandler.asString()) .completeOnTimeout(errorResponse, 10, TimeUnit.SECONDS) .thenAccept(response -> ...);
jdk.incubator.httpclientjava.net.http, with very minor API changes
HttpRequest.BodyProcessor.fromString(data) → HttpRequest.BodyPublishers.ofString(data)
URLEncloder, MIME multipartthenAccept lambda?
ExecutorService pool = Executors.newFixedThreadPool(NTHREADS);
HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.executor(pool)
.build()
.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenAccept(response -> . . .);
pool
String markdown = ````Writing about JavaScript
```
alert("JavaScript");
```
in Markdown```````` followed by newline?
... String myNameInABox = ` +-----+ | Cay | +-----+`;
String myNameInABox = `
+-----+
| Cay |
+-----+
`;
`` could be confused with empty string`` hard to see, hard to typeString myNameInABox = """
+-----+
| Cay |
+-----+
""";""" required\n\newline and \s escape sequences overcome zealous space stripping" in """| Multiline | Raw | Interpolation | Postprocessing |
| Yes | No | No | No |

switch
str(i) match {
case '+' | '-' => sign = 44 - ch
case ch if Character.isDigit(ch) => digit = Character.digit(ch, 10)
case SPACE => -1 // Uppercase for constants
case _ => sign = 0
}obj match {
case x: Int => x
case s: String => Integer.parseInt(s)
case _: BigInt => Int.MaxValue // Caution: not case BigInt
case _ => 0
}arr match {
case Array() => 0
case Array(x, 0) => x
case Array(x, rest @ _*) => rest.min
}val Array(first, second, rest @ _*) = arr for ((k, "") <- System.getProperties())

ch = obj instanceof String s && !s.isEmpty() ? s.charAt(0) : ' '
case String s case Point(var x, var y) case Point(var x, 0) case Point(var x, _) case String s && !s.isEmpty()

int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
? : ->default ->
->?
case TUESDAY -> { logger.info("Tuesday"); 7 }
x -> x * x
x -> { logger.info("Dare to be square"); return x * x }
case TUESDAY -> { logger.info("Tuesday"); return 7; }case TUESDAY -> { logger.info("Tuesday"); break 7; } // JDK 12case ... -> {
for (int i = 0; i < a.length; i++) {
if (a[i] == x) break i; // Error
}
break -1;
}case ... -> { ...; break out; } // A labeled break?
yield
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> // Multiple case labels
numLetters = 6; // No fallthrough
case TUESDAY -> {
logger.info("Tuesday");
numLetters = 7;
}
case THURSDAY, SATURDAY ->
numLetters = 8;
default ->
numLetters = 9;
}

int numLetters = switch(day) {
case MONDAY, FRIDAY, SUNDAY:
yield 6;
case TUESDAY:
logger.info("Tuesday");
yield 7;
case THURSDAY:
logger.info("Thursday"); // Yay! Fallthrough
case SATURDAY:
yield 8;
default:
yield 9;
};| Expression | Statement | |
| No fallthrough | int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
default -> 9;
}; |
switch (day) {
case MONDAY, FRIDAY, SUNDAY ->
numLetters = 6;
case TUESDAY -> {
logger.info("Tuesday");
numLetters = 7;
}
case THURSDAY, SATURDAY ->
numLetters = 8;
default ->
numLetters = 9;
} |
| Fallthrough | int numLetters = switch(day) {
case MONDAY, FRIDAY, SUNDAY:
break 6;
case TUESDAY:
logger.info("Tuesday");
break 7;
case THURSDAY:
logger.info("Thursday");
case SATURDAY:
break 8;
default:
break 9;
}; |
switch(day) {
case MONDAY, FRIDAY, SUNDAY:
numLetters = 6;
break;
case TUESDAY:
logger.info("Tuesday");
numLetters = 7;
break;
case THURSDAY:
logger.info("Thursday");
case SATURDAY:
numLetters = 8;
break;
default:
numLetters = 9;
}
|

| Statement | Expression | |
| Two-way branch | if/else |
? : |
| Multi-way branch | switch |
switch |
int numLetters = day ??
MONDAY, FRIDAY, SUNDAY -> 6 :
TUESDAY -> 7 :
THURSDAY, SATURDAY -> 8 :
9;
switch: Jump table with binary search

git clone https://github.com/openjdk/loom cd loom git checkout fibers sh configure make images
FiberScope scope = FiberScope.open();
for (int i = 1; i <= NTASKS; i++) {
int n = i;
scope.schedule(() -> run(n));
}
scope.close(); // Autocloseable—can use try-with-resources
Thread.sleep makes the current fiber sleep:public static void run(int n) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(n);
}
goto
go myfunc(); new Thread(this::myfunc).start();
goto with branches, loops, functions
FiberScope scope = FiberScope.open();
for (int i = 1; i <= NTASKS; i++) {
scope.schedule(this::myfunc);
}
scope.close();
static FiberScope open(Instant deadline, Option...options) static FiberScope open(Duration timeout, Option...options)

fiber.cancel() to set cancel statusFiber.cancelled() InterruptedException/IOException when cancelledFiberScope constructor
CANCEL_AT_CLOSE: Closing scope cancels all scheduled fibers instead of blockingPROPAGATE_CANCEL: If owning fiber is canceled, any newly scheduled fibers automatically canceledIGNORE_CANCEL: Scheduled fibers can't be canceledPROPAGATE_CANCEL, IGNORE_CANCEL inherited from parent scope
