Java >> Java tutorial >  >> Java

Brug af Records i Java

Java 14 introducerer en ny funktion kaldet Records. I Java er Record en speciel type Java-klasse. Det er beregnet til at indeholde rene uforanderlige data i den. Syntaksen for en post er kortfattet og kort sammenlignet med en normal klasse

I dette indlæg vil jeg forklare, hvorfor vi har brug for Java-poster, og hvordan man bruger dem.

Hvorfor Java Records?

Når du skriver en Java-klasse, skal du tilføje en masse boilerplate-kode. Synes godt om

    1. Genter og setter for hvert felt
    2. En offentlig konstruktør
    3. Tilsidesæt hashCode() og equals() metoder for Object klasse
    4. Tilsidesæt toString() metoden for Object klasse

Så hvis du skal oprette en Java-klasse, så sig Student , vil du have alle disse funktioner inkluderet.

Et eksempel på Student klasse med boilerplate-kode er dette.
Student.java

public class Student {

   private int id;
   private String firstName;
   private String lastName;
   private int grade;

   public Student() {
   }
   public Student(int id, String firstName, String lastName, int grade) {
      this.id = id;
      this.firstName = firstName;
      this.lastName = lastName;
      this.grade = grade;
   }

   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getFirstName() {
      return firstName;
   }

   public void setFirstName(String firstName) {
      this.firstName = firstName;
   }

   public String getLastName() {
      return lastName;
   }

   public void setLastName(String lastName) {
      this.lastName = lastName;
   }

   public int getGrade() {
      return grade;
   }

   public void setGrade(int grade) {
      this.grade = grade;
   }


   @Override
   public String toString() {
      return "StudentClass{" +"id=" + id + ", firstName='" + firstName + '\'' +
      ", lastName='" + lastName + '\'' +", grade=" + grade + '}';
   }

   @Override
   public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;
      StudentClass that = (StudentClass) o;
      return id == that.id &&
          grade == that.grade &&
          Objects.equals(firstName, that.firstName) &&
          Objects.equals(lastName, that.lastName);
   }

@Override
    public int hashCode() {
      return Objects.hash(id, firstName, lastName, grade);
   }
}

Som du kan se i Student klasse, har vi getter og setter metoder for hvert felt. Vi har en tom konstruktør, en parametriseret konstruktør og så videre.

Hvis du bruger en IDE, såsom Intelli J, kan disse boilerplate-koder genereres. Så du som programmør behøver ikke at skrive det på egen hånd, men alligevel bliver du nødt til at generere dem. Men i sidste ende bliver din klasse omfangsrig og kan forårsage læsbarhedsproblemer for andre udviklere.

Den største fordel ved at bruge poster er, at metoderne som equals()hashCode() , toString()constructor() er allerede genereret. Det gør koden kort og let at forstå.

Optag syntaks

Syntaksen for en Java Record, der modellerer en elev, er som følger.

public record Student(int id, String firstName, String lastName,int age, String PNo) {}

Den foregående kodelinje svarer til hele elevklassen, jeg viste tidligere. Dette sparer naturligvis en masse tid og reducerer koden.

Nu har jeg en elevpost med fire komponenter:id, fornavn, efternavn og karakter.

Da Java Records er en preview-sprogfunktion i JDK 14, skal du aktivere preview-funktioner for at bruge dem. En preview-sprogfunktion betyder, at selvom denne funktion er klar til at blive brugt af udviklere, kan den blive ændret i en fremtidig Java-udgivelse. De kan enten blive fjernet i en fremtidig udgivelse eller opgraderet til permanente funktioner, afhængigt af feedback modtaget om denne funktion af udviklere.

Så for at aktivere Java 14 preview-funktionerne skal du bruge --enable-preview -source 14 i kommandolinjen.

Lad os nu kompilere det sådan her.

javac – enable-preview – release 14 Student.java .

Hvordan bruger man en Java Record?

En Java-record kan bruges på samme måde som en Java-klasse.

Her er koden.

Student student1 = new Student(1,"Harry","styles",10);
Student student2 = new Student(4,"Louis","Tomlinson",11);

//to string
System.out.println(student1);
System.out.println(student2);

//accessing fields
System.out.println("First Name : " +student1.firstName());
System.out.println("Last Name : " +student1.lastName());
System.out.println(student1.toString());

//equals to
System.out.println(student1.equals(student2));

//hash code
System.out.println(student1.hashCode());

Som du kan se fra koden uden at oprette funktioner som hashCode() , equals() vi kan bruge dem i optegnelser.

Lad os nu bruge javap kommando for at se, hvad der sker, når en post kompileres.

Kør javap Student.class
fra kommandoprompt/IntelliJ-terminal

Her er koden for den dekompilerede Student klasse.

public final class Student extends java.lang.Record {
private final int id;
private final java.lang.String firstName;
private final java.lang.String lastName;
private final int grade;
public static java.lang.String UNKNOWN_GRADE

public Student(int id, java.lang.String firstName, java.lang.String lastName, int grade) {
/* compiled code */ }

public static java.lang.String getUnknownGrade() {/* compiled code */ }

public java.lang.String toString() {/* compiled code */}

public final int hashCode() {/* compiled code */}

public final boolean equals(java.lang.Object o) {/* compiled code */ }

public int id() {/* compiled code */ }

public java.lang.String firstName() {/* compiled code */ }

public java.lang.String lastName() {/* compiled code */}

public int grade() {/* compiled code */}
}

Som du kan se i den foregående kode, blev der ikke oprettet nogen sættermetoder. Dette skyldes, at typen af ​​post er endelig og uforanderlig. Bemærk også, at navnene på getter-metoderne ikke indledes med get . I stedet indeholder de kun attributnavnet.

Endnu vigtigere, bemærk, at Student klasse udvider, java.lang.Record . Alle Java Records udvider implicit java.lang.Record klasse. Du kan dog ikke direkte forlænge java.lang.Record klasse i din kode.

Compileren vil afvise forsøget på denne måde:

$ javac – enable-preview -source 14 Student.java

Student.java:3: error: records cannot directly extend Record
public final class Student extends Record {
             ^
Note: Student.java uses preview language features.
Note: Recompile with -Xlint:preview for details.
1 error

Bemærk også i den dekompilerede klasse, at en erklærer metoder som equals()hashCode() , og toString() at være abstrakt. Disse abstrakte metoder er afhængige af invokedynamic dynamisk at påberåbe sig den passende metode, som indeholder den implicitte implementering. Du kan finde mere information om invokedynamic her.

Desuden er alle felter i posterklæringen angivet som endelige.

Forekomstmetoder i post

Ligesom java-klasser kan vi også inkludere metoder i en postdefinition. Her er et eksempel på definitionen af ​​Student Java Record fra tidligere afsnit. Jeg har tilføjet en instansmetode ved navn nameAsUpperCase() .

public record Student(int id,String firstName,String lastName,int grade) {

public String nameAsUpperCase(){
return firstName.toUpperCase();
}

}

Ved blot at kalde funktionen nameAsUpperCase() vi får fornavnet med stort bogstav.

Testkoden er denne.

System.out.println("First Name : " +student1.nameAsUpperCase());

Lad os køre koden og se outputtet.

Statiske metoder i registrering

Vi kan også tilføje statiske metoder og variabler i postdefinitionen.

public record Student(int id, String firstName,String lastName,int grade) {
public static String UNKNOWN_GRADE = "grade not known" ;

public static String getUnknownGrade() {
    return UNKNOWN_GRADE;
 }
}

Fra hovedklassen kan vi kalde getUnknownGrade() funktion.

Testkoden er denne.

System.out.println(student1.getUnknownGrade());

Udgangen er som følger.

Vi kan også tilføje konstruktører i postdefinitionen. Der er tre typer postkonstruktører. De er kompakte, kanoniske og brugerdefinerede konstruktører.

En kompakt konstruktør har ingen argumenter. Den har ikke engang parenteser.

Dette er et typisk eksempel på en kompakt konstruktør.

public Student{
if(id < 0)
    throw new IllegalArgumentException("student id cannot be negative");
}

Da id ikke kan være negativt, tilføjer jeg en undtagelse her.

Dette er testkoden.

Student student = new Student(-1,"loius","lee",4);
System.out.println(student);

Som du kan se på outputtet, får vi en fejlmeddelelse.

En kanonisk konstruktør tager alle medlemmerne som sine parametre.

Hvis du ændrer en kanonisk konstruktør, bliver den en brugerdefineret konstruktør.

Du kan kun gå efter en af ​​de tre ovennævnte konstruktører på én gang. Dette skyldes, at tilføjelse af flere konstruktører til en post som en almindelig klasse ikke er tilladt.

Oversigt

Java Records er en fantastisk måde at reducere standardkode uden at ofre pålideligheden af ​​en uforanderlig klasse.

Hvis du har skrevet kode til virksomhedsapplikationer, er du muligvis stødt på Lombok, et værktøj til også at reducere kedelkode.

Der har været tale om, at Java Records skal erstatte biblioteker som Lombok, men det er ikke tilfældet. Begge er forskellige værktøjer til forskellige ting. Der er en vis overfladisk overlapning, men lad det ikke distrahere dig.

Lombok eller lignende kedelkodegenereringsbiblioteker handler i høj grad om syntaktisk bekvemmelighed. De er typisk forudindlæst med nogle kendte nyttige kodemønstre. De automatiserer mønstrene i henhold til de annoteringer, du tilføjer til din klasse. Sådanne biblioteker handler udelukkende om bekvemmeligheden ved at implementere databærende klasser.

På den anden side er Java Records en semantisk funktion. De giver et førsteklasses middel til modellering af data-kun aggregater. De er også designet til at lukke et muligt hul i Javas typesystem. Derudover, som vi så, leverer Records syntaks på sprogniveau for et fælles programmeringsmønster.


Java tag