Sleutelwoord voor Java 14-records

1. Inleiding

Het doorgeven van onveranderlijke gegevens tussen objecten is een van de meest voorkomende, maar alledaagse taken in veel Java-toepassingen.

Vóór Java 14 vereiste dit de creatie van een klasse met standaardvelden en methoden, die vatbaar waren voor triviale fouten en verwarde bedoelingen.

Met de release van Java 14 kunnen we nu records gebruiken om deze problemen op te lossen.

In deze tutorial we kijken naar de grondbeginselen van records, inclusief hun doel,gegenereerde methoden en maatwerktechnieken.

2. Doel

Gewoonlijk schrijven we klassen die eenvoudigweg gegevens bevatten, zoals databaseresultaten, queryresultaten of informatie van een service.

In veel gevallen zijn deze gegevens onveranderlijk, aangezien onveranderlijkheid verzekert de geldigheid van de gegevens zonder synchronisatie.

Om dit te bereiken, maken we dataklassen met het volgende:

  1. privaat, laatste veld voor elk gegeven
  2. getter voor elk veld
  3. openbaar constructor met een overeenkomstig argument voor elk veld
  4. is gelijk aan methode die terugkeert waar voor objecten van dezelfde klasse als alle velden overeenkomen
  5. hashCode methode die dezelfde waarde retourneert als alle velden overeenkomen
  6. toString methode die de naam van de klasse en de naam van elk veld en de bijbehorende waarde bevat

We kunnen bijvoorbeeld een simple Persoon dataklasse, met een naam en een adres:

openbare klasse Persoon {privé finale Tekenreeksnaam; privé laatste String-adres; publieke persoon (stringnaam, stringadres) {this.name = naam; this.address = adres; } @Override public int hashCode () {return Objects.hash (naam, adres); } @Override public boolean equals (Object obj) {if (this == obj) {return true; } else if (! (obj instanceof Person)) {return false; } else {Person other = (Person) obj; retourneer Objects.equals (naam, andere.naam) && Objects.equals (adres, ander.adres); }} @Override public String toString () {return "Person [name =" + name + ", address =" + address + "]"; } // standaard getters}

Hoewel dit ons doel bereikt, zijn er twee problemen:

  1. Er is veel standaardcode
  2. We verdoezelen het doel van onze klas - om een ​​persoon te vertegenwoordigen met een naam en adres

In het eerste geval moeten we hetzelfde vervelende proces herhalen voor elke dataklasse, monotoon een nieuw veld creëren voor elk stuk data, creëren is gelijk aan, hashCode, en toString methoden en het maken van een constructor die elk veld accepteert.

Hoewel IDE's automatisch veel van deze klassen kunnen genereren, ze slagen er niet in om onze klassen automatisch bij te werken wanneer we een nieuw veld toevoegen. Als we bijvoorbeeld een nieuw veld toevoegen, moeten we onze is gelijk aan methode om dit veld op te nemen.

In het tweede geval de extra code verhult dat onze klasse gewoon een dataklasse is dat heeft er twee Draad velden: naam en adres.

Een betere benadering zou zijn om expliciet te verklaren dat onze klasse een dataklasse is.

3. De basis

Vanaf JDK 14 kunnen we onze repetitieve dataklassen vervangen door records. Records zijn onveranderlijke gegevensklassen waarvoor alleen het type en de naam van velden nodig zijn.

De is gelijk aan, hashCode, en toString methoden, evenals de privaat, laatste velden, en openbaar constructor, worden gegenereerd door de Java-compiler.

Om een Persoon record gebruiken we de Vermelding trefwoord:

openbaar record persoon (tekenreeksnaam, tekenreeksadres) {}

3.1. Constructor

Met behulp van records wordt een openbare constructor - met een argument voor elk veld - voor ons gegenereerd.

In het geval van onze Persoon record, is de equivalente constructor:

publieke persoon (stringnaam, stringadres) {this.name = naam; this.address = adres; }

Deze constructor kan op dezelfde manier als een klasse worden gebruikt om objecten uit het record te instantiëren:

Persoon persoon = nieuwe persoon ("John Doe", "100 Linda Ln.");

3.2. Getters

We ontvangen ook gratis openbare getters-methoden waarvan de namen overeenkomen met de naam van ons vakgebied.

In onze Persoon record, dit betekent een naam() en adres() getter:

@Test openbare ongeldig gegevenValidNameAndAddress_whenGetNameAndAddress_thenExpectedValuesReturned () {String name = "John Doe"; String adres = "100 Linda Ln."; Persoon persoon = nieuwe persoon (naam, adres); assertEquals (naam, person.name ()); assertEquals (adres, persoon.adres ()); }

3.3. is gelijk aan

Bovendien, een is gelijk aan methode is voor ons gegenereerd.

Deze methode keert terug waar als het geleverde object van hetzelfde type is en de waarden van al zijn velden overeenkomen:

@Test openbare ongeldig gegevenSameNameAndAddress_whenEquals_thenPersonsEqual () {String name = "John Doe"; String adres = "100 Linda Ln."; Persoon person1 = nieuwe persoon (naam, adres); Persoon person2 = nieuwe persoon (naam, adres); assertTrue (person1.equals (person2)); }

Als een van de velden tussen twee verschillen Persoon gevallen, de is gelijk aan methode zal terugkeren false.

3.4. hashCode

Vergelijkbaar met onze is gelijk aan methode, een overeenkomstige hashCode methode wordt ook voor ons gegenereerd.

Onze hashCode methode retourneert dezelfde waarde voor twee Persoon objecten als alle veldwaarden voor beide objecten overeenkomen (behoudens botsingen vanwege de verjaardagsparadox):

@Test openbare leegte gegevenSameNameAndAddress_whenHashCode_thenPersonsEqual () {String name = "John Doe"; String adres = "100 Linda Ln."; Persoon person1 = nieuwe persoon (naam, adres); Persoon person2 = nieuwe persoon (naam, adres); assertEquals (person1.hashCode (), person2.hashCode ()); } 

De hashCode waarde zal verschillen als een van de veldwaarden verschilt.

3.5. toString

Ten slotte ontvangen we ook eentoString methode die resulteert in een tekenreeks met de naam van het record, gevolgd door de naam van elk veld en de bijbehorende waarde tussen vierkante haken.

Daarom instantiëren van een Persoon met een naam van "John Doe" en een adres van '100 Linda Ln.”Resulteert in het volgende toString resultaat:

Persoon [naam = John Doe, adres = 100 Linda Ln.]

4. Constructeurs

Hoewel er een openbare constructor voor ons wordt gegenereerd, kunnen we onze constructorimplementatie nog steeds aanpassen.

Deze aanpassing is bedoeld om te worden gebruikt voor validatie en moet zo eenvoudig mogelijk worden gehouden.

We kunnen er bijvoorbeeld voor zorgen dat de naam en adres verstrekt aan onze Persoon record zijn niet nul met behulp van de volgende constructorimplementatie:

publiek record Persoon (Stringnaam, Stringadres) {publieke persoon {Objects.requireNonNull (naam); Objects.requireNonNull (adres); }}

We kunnen ook nieuwe constructors maken met verschillende argumenten door een andere lijst met argumenten op te geven:

publiek record Persoon (Stringnaam, Stringadres) {publieke persoon (Stringnaam) {this (naam, "Onbekend"); }}

Net als bij klassenconstructeurs, naar de velden kan worden verwezen met behulp van de dit trefwoord (bijvoorbeeld, deze naam en dit adres) en de argumenten komen overeen met de naam van de velden (dat is, naam en adres).

Let daar op het maken van een constructor met dezelfde argumenten als de gegenereerde openbare constructor is geldig, maar dit vereist dat elk veld handmatig wordt geïnitialiseerd:

openbaar record Persoon (Stringnaam, Stringadres) {publieke persoon (Stringnaam, Stringadres) {this.name = naam; this.address = adres; }}

Bovendien, het declareren van een constructor zonder argument en een met een argumentenlijst die overeenkomt met de gegenereerde constructor resulteert in een compilatiefout.

Daarom zal het volgende niet compileren:

publiek record Persoon (Stringnaam, Stringadres) {publieke persoon {Objects.requireNonNull (naam); Objects.requireNonNull (adres); } publieke persoon (stringnaam, stringadres) {this.name = naam; this.address = adres; }}

5. Statische variabelen en methoden

Net als bij gewone Java-lessen, we kunnen ook statische variabelen en methoden in onze records opnemen.

We declareren statische variabelen met dezelfde syntaxis als een klasse:

publiek record Persoon (Stringnaam, Stringadres) {publieke statische String ONBEKEND_ADDRESS = "Onbekend"; }

Evenzo declareren we statische methoden met dezelfde syntaxis als een klasse:

openbaar record Persoon (Stringnaam, Stringadres) {publieke statische persoon naamloos (Stringadres) {retourneer nieuwe persoon ("Naamloos", adres); }}

We kunnen dan verwijzen naar zowel statische variabelen als statische methoden met behulp van de naam van het record:

Person.UNKNOWN_ADDRESS Person.unnamed ("100 Linda Ln.");

6. Conclusie

In dit artikel hebben we gekeken naar de Vermelding trefwoord geïntroduceerd in Java 14, inclusief hun fundamentele concepten en fijne kneepjes.

Door records te gebruiken - met hun door de compiler gegenereerde methoden - kunnen we de standaardcode verminderen en de betrouwbaarheid van onze onveranderlijke klassen verbeteren.

De code en voorbeelden voor deze tutorial zijn te vinden op GitHub.