# Vad är Java Records?

16 juni 2021 | https://www.ribomation.se/blog/2021/vad-ar-java-records/

Java version 16, som släpptes i mars, bjöd på en riktigt stor syntaktisk nyhet, nämligen Records. I korthet, är det oföränderliga (_immutable_) klasser med förenklad syntax och automatgenererade åtkomst (_access_) metoder.

Så, vad är då vitsen med detta då? Reflektera över hur många värdeförmedlande klasser du skrivit. Du vet, en klass med en handfull medlemsvariabler som får värden i en konstruktor med lika många parametrar, lika många getter-metoder, en toString() method och equals() och hashCode() metoder kopplade värdemässigt till varandra. Typiska metoder man låter en IDE generera.

### Syntax

Med records i Java 16 kan du fokusera på det väsentliga, nämligen medlemsvariablerna (_properties_) och låta kompilatorn ta hand om resten.

```java
record Person(String name, int age) {}
```

Det som är helt nytt i syntaxen ovan, är att du deklarerar medlemsvariablerna inom parenteser. Fortsättningsvis, använder jag `jshell` för att visa kod-fragment och utskrifter.

```bash
$ jshell
|  Welcome to JShell -- Version 16.0.1
jshell> record Person(String name, int age) {}
|  created record Person
```

Instansiering är dock på klassiskt vis med new. Notera också nedan, att kompilatorn genererat getters för medlemsvariablerna.

```bash
jshell> var p = new Person("Nisse Hult", 42);
p ==> Person[name=Nisse Hult, age=42]

jshell> System.out.printf("%s, %d %n", p.name(), p.age());
Nisse Hult, 42
```

### Auto-Metoder

Förutom getters, så genereras också `toString` samt `equals` & `hashCode` metoder.

```bash
jshell> System.out.println(p.toString());
Person[name=Nisse Hult, age=42]
```

```bash
jshell> var q = new Person("Nisse Hult", 42);
q ==> Person[name=Nisse Hult, age=42]
```

```bash
jshell> System.out.println(p.equals(q));
true
```

```bash
jshell> System.out.println(q.hashCode());
-296696321
```

### Restriktioner

Det finns dock en del restriktioner att vara observant på. Records kan varken vara subklass eller superklass, ej heller abstrakt. Det går inte att deklarera ytterligare instansvariabler inuti record-kroppen.

Emellertid, kan en record innehålla static variabler och static metoder, samt ett static init-block (_klasskonstruktor_). Vidare, så kan en record implementera interface och vara generisk. Det går också att annotera en record.

### Omdefinition av Getters

Det är möjligt att omdefiniera (_override_) en eller flera getter, för att transformera det värde som ska returneras. Tänk på att en record är immutable, så det finns inga setters att göra override på.

```java
record Person(String name, int age) {
  public String name() {
    return name.toUpperCase();
  }
}
```

### Förenklad Konstruktor

Behöver man kontrollera indata då en record skapas kan man deklarera en syntaktisk förenklad konstruktor, (_compact constructor_). I denna lägger man enbart verifieringskod. Den klassiska värdekopierings-koden (`this.var = var`) genereras av kompilator. Observera att denna form av konstruktor saknar parameter-parenteser!

```java
record Person(String name, int age) {
  public Person {
    if (age < 0) 
      throw new IllegalArgumentException("Negative age: " + age);
  }
}
```

### Inner & Local Records

Precis som man kan deklarera klasser inuti en annan klass (_inner_), samt inuti en metod (_local_), så kan man göra detta också för en record.

I praktiken, är det sällan man skapar lokala klasser, eftersom antalet kodrader i omslutande metod skulle bli för stort. Med en record deklaration på en kodrad, blir det betydligt mer användbart att skapa hjälptyper som kan aggregera värden under någon form av sammanställning i en stream pipeline.

### Installation av Java 16

Enklaste sättet att installera Java och snabbt kunna växla mellan olika versioner är att använda SDKMAN i ett BASH fönster, såsom t.ex. GIT-BASH. Först installerar man SDKMAN

```bash
curl -s "https://get.sdkman.io" | bash
```

Sen, installerar man önskad Java version

```bash
sdk install java 16.0.1.hs-adpt
java --version
```

Alternativt, laddar man ned en installer från AdoptOpenJDK.
