Java >> Java Program >  >> Java

Använda Records i Java

Java 14 introducerar en ny funktion som heter Records. I Java är Record en speciell typ av Java-klass. Den är avsedd att hålla ren oföränderlig data i den. Syntaxen för en post är koncis och kort jämfört med en normal klass

I det här inlägget kommer jag att förklara varför vi behöver Java-poster och hur man använder dem.

Varför Java Records?

När du skriver en Java-klass måste du lägga till en hel del kod. Gilla

    1. Getter och seter för varje fält
    2. En offentlig konstruktör
    3. Åsidosätt hashCode() och equals() metoder för Object klass
    4. Åsidosätt toString() metod för Object klass

Så om du måste skapa en Java-klass, säg Student , kommer du att ha alla dessa funktioner inkluderade.

Ett exempel Student klass med boilerplate-kod är detta.
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 klass, vi har getter- och settermetoder för varje fält. Vi har en tom konstruktor, en parametriserad konstruktor och så vidare.

Om du använder en IDE, såsom Intelli J, kan dessa boilerplate-koder genereras. Så du som programmerare behöver inte skriva det på egen hand, men ändå måste du generera dem. Men i slutändan blir din klass skrymmande och kan orsaka läsbarhetsproblem för andra utvecklare.

Den största fördelen med att använda poster är att metoder som equals()hashCode() , toString()constructor() är redan genererade. Det gör koden kort och lätt att förstå.

Spela in syntax

Syntaxen för en Java Record som modellerar en student är följande.

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

Föregående kodrad motsvarar hela studentklassen jag visade tidigare. Detta sparar uppenbarligen mycket tid och minskar koden.

Nu har jag en studentpost med fyra komponenter:id, förnamn, efternamn och betyg.

Eftersom Java Records är en språkfunktion för förhandsvisning i JDK 14, måste du aktivera förhandsgranskningsfunktioner för att kunna använda dem. En språkfunktion för förhandsvisning innebär att även om den här funktionen är redo att användas av utvecklare, kan den ändras i en framtida Java-utgåva. De kan antingen tas bort i en framtida version eller uppgraderas till permanenta funktioner, beroende på feedback från utvecklarna om den här funktionen.

Så för att aktivera Java 14-förhandsgranskningsfunktionerna måste du använda --enable-preview -source 14 på kommandoraden.

Låt oss nu kompilera det så här.

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

Hur använder man en Java-post?

En Java-post kan användas på samma sätt som en Java-klass.

Här är 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 av koden utan att skapa funktioner som hashCode() , equals() vi kan använda dem i register.

Nu ska vi använda javap kommando för att se vad som händer när en post kompileras.

Kör javap Student.class
från kommandotolken/IntelliJ-terminalen

Här är koden för den dekompilerade Student klass.

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 föregående kod skapades inga sättermetoder. Detta beror på att typen av post är slutgiltig och oföränderlig. Observera också att namnen på gettermetoderna inte föregås av get . Snarare innehåller de bara attributnamnet.

Ännu viktigare, notera att Student klass utökas, java.lang.Record . Alla Java-poster utökar implicit java.lang.Record klass. Du kan dock inte förlänga java.lang.Record direkt klass i din kod.

Kompilatorn kommer att avvisa försöket, så här:

$ 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

Observera även i den dekompilerade klassen att en deklarerar metoder som equals()hashCode() och toString() att vara abstrakt. Dessa abstrakta metoder förlitar sig på invokedynamic att dynamiskt anropa den lämpliga metoden som innehåller den implicita implementeringen. Du kan hitta mer information om invokedynamic här.

Dessutom anges alla fält i postdeklarationen som slutgiltiga.

Instansmetoder i post

Precis som java-klasser kan vi också inkludera metoder i en postdefinition. Här är ett exempel på definitionen av Student Java Record från tidigare avsnitt. Jag har lagt till en instansmetod som heter nameAsUpperCase() .

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

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

}

Genom att helt enkelt anropa funktionen nameAsUpperCase() vi får förnamnet med versaler.

Testkoden är denna.

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

Låt oss köra koden och se resultatet.

Statiska metoder i posten

Vi kan också lägga till statiska metoder och 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;
 }
}

Från huvudklassen kan vi anropa getUnknownGrade() funktion.

Testkoden är denna.

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

Utgången är som följer.

Vi kan också lägga till konstruktörer i postdefinitionen. Det finns tre typer av postkonstruktörer. De är kompakta, kanoniska och anpassade konstruktörer.

En kompakt konstruktör har inga argument. Den har inte ens parentes.

Detta är ett typiskt exempel på en kompakt konstruktör.

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

Eftersom id inte kan vara negativt lägger jag till ett undantag här.

Det här är testkoden.

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

Som du kan se från utdata får vi ett felmeddelande.

En kanonisk konstruktor tar alla medlemmar som sina parametrar.

Om du ändrar en kanonisk konstruktor blir den en anpassad konstruktor.

Du kan bara gå till någon av de tre konstruktörerna som nämns ovan samtidigt. Detta beror på att det inte är tillåtet att lägga till flera konstruktorer till en post som en vanlig klass.

Sammanfattning

Java Records är ett utmärkt sätt att reducera standardkod utan att offra tillförlitligheten hos en oföränderlig klass.

Om du har skrivit kod för företagsapplikationer kan du ha stött på Lombok, ett verktyg för att även reducera koden.

Det har pratats om att Java Records ska ersätta bibliotek som Lombok, men det är inte så. Båda är olika verktyg för olika saker. Det finns en viss ytlig överlappning, men låt det inte distrahera dig.

Lombok eller liknande kodgenereringsbibliotek handlar till stor del om syntaktisk bekvämlighet. De är vanligtvis förladdade med några kända användbara kodmönster. De automatiserar mönstren, enligt kommentarerna du lägger till i din klass. Sådana bibliotek handlar enbart om bekvämligheten med att implementera databärande klasser.

Å andra sidan är Java Records en semantisk funktion. De tillhandahåller ett förstklassigt sätt för modellering av endast dataaggregat. De är också utformade för att täppa till en möjlig lucka i Javas typsystem. Dessutom, som vi såg, tillhandahåller Records syntax på språknivå för ett vanligt programmeringsmönster.


Java-tagg