מחלקת רשומות Java 14

ג'אווה 14 הציגה דרך חדשה ליצירת מחלקות בשם רשומות. במדריך זה, נלמד:

  • למה אנו צריכים רשומות ג'אווה
  • כיצירת רשומות ושימוש בהן
  • דרך לדרוס ולהרחיב מחלקות רשומות

קריאה מומלצת: תכונות ג'אווה 14

למה אנו צריכים רשומות ג'אווה?

אחת מהתלונות הנפוצות בג'אווה הייתה הרתיעות שלה. אם עליך ליצור מחלקת POJO פשוטה, זה מחייב קוד מקור עזר כדלקמן.

  • שדות פרטיים
  • שיטות Getter ו-Setter
  • בנאים
  • שיטות hashCode(), equals(), ו- toString().

הרתיעות הזו היא אחת הסיבות לעניין גבוה ב- Kotlin וב- Project Lombok.

למעשה, הקיצור הפשוט של כתיבת שיטות גנריות אלו בכל פעם הוביל להקלות ביצירתן ב-IDE של ג'אווה כמו Eclipse ו- IntelliJ IDEA.

הנה צילום מסך המראה אפשרות ב- Eclipse IDE ליצירת השיטות הסמליות למחלקה.

Eclipse Shortcuts to Generate Ceremonial Methods

רשומות ג'אווה מיועדות להסיר את הרתיעות הזו על ידי ספקן מבנה קומפקטי ליצירת מחלקות POJO.

כיצד ליצור רשומות Java

רשומות Java היא תכונה תצוגה, שפותחה תחת JEP 359. לכן, נדרשות שני דברים כדי ליצור רשומות בפרויקטי Java שלך.

  1. JDK 14 מותקן. אם אתה משתמש ב-IDE, אז עליו לספק תמיכה ב-Java 14 גם כן. Eclipse ו-IntelliJ כבר מספקים תמיכה ב-Java 14, כך שאנחנו טובים כאן.
  2. הפעל תכונת תצוגה: כברירת מחדל, התכונות התצוגה מושבתות. ניתן להפעיל אותן ב-Eclipse מתוך הגדרות קומפילציה של פרויקט Java.
Java 14 Enable Preview Feature In Eclipse

ניתן להפעיל תכונות תצוגה של Java 14 בשורת הפקודה באמצעות האפשרות --enable-preview -source 14.

נניח שאני רוצה ליצור מחלקת מודל של עובד. זה יראה משהו דומה לקוד הבא.

package com.journaldev.java14;

import java.util.Map;

public class Employee {

	private int id;
	private String name;
	private long salary;
	private Map<String, String> addresses;

	public Employee(int id, String name, long salary, Map<String, String> addresses) {
		super();
		this.id = id;
		this.name = name;
		this.salary = salary;
		this.addresses = addresses;
	}

	public int getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public long getSalary() {
		return salary;
	}

	public Map<String, String> getAddresses() {
		return addresses;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((addresses == null) ? 0 : addresses.hashCode());
		result = prime * result + id;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + (int) (salary ^ (salary >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Employee other = (Employee) obj;
		if (addresses == null) {
			if (other.addresses != null)
				return false;
		} else if (!addresses.equals(other.addresses))
			return false;
		if (id != other.id)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (salary != other.salary)
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + ", addresses=" + addresses + "]";
	}

}

פיו, זהו מעל 70 שורות של קוד שנוצר אוטומטית. עכשיו בוא נראה כיצד ליצור מחלקת רשומה של עובד, שבעצם מספקת את אותן תכונות.

package com.journaldev.java14;

import java.util.Map;

public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
}

וואו, זה לא יכול להיות קצר יותר מזה. כבר אוהב מחלקות רשומות.

עכשיו, בוא נשתמש בפקודת javap כדי להבין מה קורה מאחורי הקלעים כאשר רשומה מקומפלת.

# javac --enable-preview -source 14 EmpRecord.java
Note: EmpRecord.java uses preview language features.
Note: Recompile with -Xlint:preview for details.

# javap EmpRecord      
Compiled from "EmpRecord.java"
public final class EmpRecord extends java.lang.Record {
  public EmpRecord(int, java.lang.String, long, java.util.Map<java.lang.String, java.lang.String>);
  public java.lang.String toString();
  public final int hashCode();
  public final boolean equals(java.lang.Object);
  public int id();
  public java.lang.String name();
  public long salary();
  public java.util.Map<java.lang.String, java.lang.String> addresses();
}
# 
Java Record Class Details

# javac enablepreview source 14 EmpRecord.java

# javap EmpRecord

אם ברצונך לקבל פרטים פנימיים נוספים, הרץ את הפקודה javap עם האפשרות -v.

  1. A Record class is final, so we can’t extend it.
  2. # javap -v EmpRecord
  3. נקודות חשובות אודות קבוצות רשומות
  4. קבוצות הרשומות מרחיבות באופן אמיפיטי את המחלקה java.lang.Record.
  5. A single constructor is created with all the fields specified in the record definition.
  6. כל השדות שמוגדרים בהכרזה על קבוצת רשומות הם קבועים.
  7. שדות הרשומה הם בטוחים מבחינת "עמידות" קצרה ותלויים בסוג. לדוגמה, ניתן לשנות את שדה הכתובת על ידי גישה אליו ובצורה זו לעדכן אותו.

מחלקת הרשומות מספקת באופן אוטומטי שיטות גישה לשדות. שם השיטה הוא זהה לשם השדה, ולא כמו בשיטות הגטר הגנריות והרגילות.

מחלקת הרשומה מספקת גם את המימושים של hashCode(), equals(), ו- toString().

package com.journaldev.java14;

public class RecordTest {

	public static void main(String[] args) {
		
		EmpRecord empRecord1 = new EmpRecord(10, "Pankaj", 10000, null);
		EmpRecord empRecord2 = new EmpRecord(10, "Pankaj", 10000, null);

		שימוש ברשומות בתוך תוכנית Java
		System.out.println(empRecord1);
		
		בואו נסתכל על דוגמה פשוטה לשימוש במחלקת ה- EmpRecord שלנו.
		System.out.println("Name: "+empRecord1.name()); 
		System.out.println("ID: "+empRecord1.id());
		
		// toString()
		System.out.println(empRecord1.equals(empRecord2));
		
		// גישה לשדות
		System.out.println(empRecord1 == empRecord2);		
	}
}

// equals()

EmpRecord[id=10, name=Pankaj, salary=10000, addresses=null]
Name: Pankaj
ID: 10
true
false

// hashCode()

פלט:

אובייקט ה- Record עובד באותו אופן כמו כל מחלקת מודל, אובייקט נתונים וכו '

public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
	
	public EmpRecord {
		if (id < 0)
			throw new IllegalArgumentException("employee id can't be negative");

		if (salary < 0)
			throw new IllegalArgumentException("employee salary can't be negative");
	}

}

הרחבת בנאי רשומות

EmpRecord empRecord1 = new EmpRecord(-10, "Pankaj", 10000, null);

לעיתים, נרצה לבצע תיקונים או להוסיף לוגיקה בבנאי ה-constructor. לדוגמה, מזהה העובד והמשכורת לא יכולים להיות שליליים. הבנאי הדיפולטי לא יכיל את האימות הזה. נוכל ליצור בנאי קומפקטי במחלקת ה- record. קוד הבנאי הזה יוצב בתחילת הבנאי האוטומטי.

Exception in thread "main" java.lang.IllegalArgumentException: employee id can't be negative
	at com.journaldev.java14.EmpRecord.<init>(EmpRecord.java:9)

אם ניצור את ה- EmpRecord כמו בקוד הבא:

נקבל חריגת זמן ריצה כך:

public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {

	public int getAddressCount() {
		if (this.addresses != null)
			return this.addresses().size();
		else
			return 0;
	}
}

האם ניתן להכיל שיטות במחלקות רשומות?

כן, ניתן ליצור שיטה במחלקות רשומות.

אך, המחלקות הרשומות נועדו להיות נושאי נתונים. עלינו להימנע מיצירת שיטות עזר במחלקת רשומה. לדוגמה, השיטה לעיל ניתנת ליצירה במחלקת יעוץ.

אם אתה חושב שיש לך צורך בשיטה עבור מחלקת הרשומה שלך, חשוב האם באמת זקוק אתה למחלקת רשומה?

Source:
https://www.digitalocean.com/community/tutorials/java-records-class