# Java version 19 är här

29 september 2022 | https://www.ribomation.se/blog/2022/java-version-19-ar-har/

Java JDK version 19 släpptes i förra veckan. Nu mera släpper Oracle en ny version två gånger per år (vår och höst). Version 19 innehåller ett antal förhandsversioner av funktionalitet (_preview features_), som vi ska kika på i detta inlägg.

Ny funktionalitet i Java brukar oftast utvecklas i projektform, vilket innebär att det inom ett dylikt projekt kan föras en diskussion om nya egenskaper och olika implementationsförslag kan utvärderas. Med tiden kristalliseras vad man vill gå vidare med för inkorporering i språket Java respektive dess bibliotek.

De projekt som är aktuella för Java 19 är

*   Project **Amber**: pattern matching, switch expressions, records
*   Project **Loom**: virtual threads, co-routines
*   Project **Panama**: invocation of native code, replacement of JNI

Vad innebär preview?
--------------------

En förhandsversion av en funktionalitet i Java innebär att vissa saker kan förändras. Såsom "_Pattern matching for switch_" är inne på den tredje förhandsversionen.

För att kunna kompilera och exekvera ett Java program som använder sig av förhandsfunktioner måste man bifoga en flagga

```shell
javac -d cls --enable-preview --release 19 MyApp.java
java -cp cls --enable-preview MyApp
```

Om det bara är en källkodsfil kan du kompilera och köra direkt

```shell
java --enable-preview --source 19 src/Amber.java
```

Förbättrad `switch`
-------------------

Sedan tidigare så har den _gamla_ `switch`\-satsen evolverat till att också formuleras som ett uttryck (_expression_). Den funktionalitet som förhandsvisas nu är matchning på type eventuellt tillsammans med ett för-villkor.

```java
Object obj = ...;
var result = switch(obj) {
  case Integer val when val < 0  -> "Negative";
  case Integer val when val == 0 -> "Zero";
  case Integer val               -> "Positive";
  default                        -> "Unknown";
};
```

Här följer ett komplett exempel. Tanken är en funktion i ett hypotetiskt system för syntax-färgning (_syntax coloring_), som tar ett objekt och returnerar en `HTML span` tag med CSS class och formaterat värde. Först har vi den klassiska versionen med en `switch`\-sats.

```java
String renderClassic(Object obj) {
    String css = "unknown";
    String txt = obj != null ? obj.toString() : "null";
    if (obj instanceof Integer || obj instanceof Long) {
        css = "integral";
        txt = Long.toString(((Number) obj).longValue());
    } else if (obj instanceof Float || obj instanceof Double) {
        css = "real";
        txt = format("%.5f", ((Number) obj).doubleValue());
    } else if (obj instanceof Boolean) {
        css = "bool";
        txt = (Boolean) obj ? "True" : "False";
    } else if (obj instanceof Date) {
        css = "date";
        txt = format("%tF", (Date) obj);
    } else if (obj instanceof String) {
        css = "string";
        txt = obj.toString();
    }
    return format("<span class=\"%s\">%s</span>", css, txt);
}
```

Matar vi denna med följande värden

```java
Object[] values = { 2 * 21, -17, 4 * atan(1),
  (42 == 40 + 2), ("Hi" + " " + "Java"), "    ",
  new Date(), Runtime.version(), null };

void test_renderClassic() {
    for (Object obj : values)
        System.out.printf("(C) %s%n", renderClassic(obj));
}
```

Blir utskriften på följande sätt

```shell
(C) <span class="integral">42</span>
(C) <span class="integral">-17</span>
(C) <span class="real">3,14159</span>
(C) <span class="bool">True</span>
(C) <span class="string">Hi Java</span>
(C) <span class="string">    </span>
(C) <span class="date">2022-09-29</span>
(C) <span class="unknown">19+36-2238</span>
(C) <span class="unknown">null</span>
```

Den moderna version börjar med att klassificera vad det är för indata och använder resultatet för att skapa en HTML span tag.

```java
String renderModern(Object obj) {
    var c = classify(obj);
    return format("<span class=\"%s\">%s</span>", c.css, c.txt);
}
```

Funktionen `classify` returnerar en `record Pair`. Records kom i Java 16, men har figurerat som förhandsversioner innan dess.

```
record Pair(String css, String txt) { }
```

Så här ser funktionen `classify` ut.

```java
Pair classify(Object obj) {
    return switch (obj) {
        case null -> 
                new Pair("unknown", "null");
        case Integer val when val < 0 -> 
                new Pair("integral negative", Integer.toString(val));
        case Integer val -> 
                new Pair("integral", Integer.toString(val));
        case Long val when val < 0 -> 
                new Pair("integral negative", Long.toString(val));
        case Long val -> 
                new Pair("integral", Long.toString(val));
        case Float val -> 
                new Pair("real", format("%.5f", val));
        case Double val -> 
                new Pair("real", format("%.5f", val));
        case Boolean val when true -> 
                new Pair("bool", val ? "True" : "False");
        case Date val -> 
                new Pair("date", format("%tF", val));
        case String val when val.isBlank() -> 
                new Pair("string blank", "_");
        case String val -> 
                new Pair("string", val);
        default -> 
                new Pair("unknown", obj.toString());
    };
}
```

Anropar vi funktionen med samma data som tidigare får vi denna utskrift.

```shell
(M) <span class="integral">42</span>
(M) <span class="integral negative">-17</span>
(M) <span class="real">3,14159</span>
(M) <span class="bool">True</span>
(M) <span class="string">Hi Java</span>
(M) <span class="string blank">_</span>
(M) <span class="date">2022-09-29</span>
(M) <span class="unknown">19+36-2238</span>
(M) <span class="unknown">null</span>
```

Destrukturering av sammansatta data
-----------------------------------

Om du programmerat i modern JavaScript (dvs EcmaScript), så kanske du känner till att man kan _packa upp_ ett sammansatt objekt.

```js
//JavaScript
const obj = {name:'Nisse', addr:{street:'Hacker Lane', city:'Perl Lake'}}
const {name, addr:{street}} = obj
console.log('%s bor på %s', name, street)
--> Nisse bor på Hacker Lane
```

Liknande egenskaper finns i andra språk. Till exempel i C++ kan man packa upp en enkel `struct` eller `std::tuple`.

```cpp
//C++
#include <iostream>
#include <string>
struct Data {
    std::string name;
    unsigned age;
};
int main() {
    auto p = Data{"Bosse", 42};
    auto [n, a] = p;
    std::cout << n << ":" << a << "\n";
}
--> Bosse:42
```

En variant på detta finns nu som en förhandsvisning, där man kan dekonstruera en `record`. Säg att vi har följande två records.

```java
record Address (String street, String city, int code) {}
record Person (String name, Address addr, int age) {}
```

Vi skapar ett person-objekt och skickar detta till funktionen `doit`.

```java
void run() {
    var p = new Person("Nisse Hult", 
                       new Address("Hacker Lane", "Javaville", 8080), 
                       42);
    doit(p);
}
```

I denna funktion packar vi upp det sammansatta objekt och plockar ut det vi behöver.

```java
void doit(Object obj) {
    if (obj instanceof Person(String n, Address(String s, String c, int o), int a))
        System.out.printf("%s lives on %s", n, s);
}
```

Kör vi programmet vår vi veta på vilken gata Nisse bor.

```shell
$ java  --enable-preview --source 19 src/Amber2.java
Note: src\Amber2.java uses preview features of Java SE 19.
Note: Recompile with -Xlint:preview for details.
Nisse Hult lives on Hacker Lane
```

I funktionen `doit`, hade vi med ett antal variabler i matchningen som inte behövdes. Snart (hoppas vi) kommer man kunna ersätta dessa med en så kallad _don't care_ variabel i form av ett understrykningstecken (`_`).

```java
if (obj instanceof Person(String n, Address(String s, String _, int _), int _))
    System.out.printf("%s lives on %s", n, s);
```

Bruket med understrykningstecken för att markera ointressanta delar kommer från språk som Prolog och Erlang (influerad av Prolog).

I nästa avsnitt ska vi kika på virtuella trådar (_virtual threads_) från project Loom.
