Records in Java

Records were a new addition in Java 14. Before that, data was typically held in a class with Getter and Setter methods. Typically, these storage classes were used to store data for objects, database results or really, any type of information that might be passed to other classes in a program.

Personally, I still prefer these classes as a lot of the data I deal with changes and changes often. But Records have their uses particularly for data that is unlikely to change.

As an example, say we have a class Student with the required data of firstname (fName), surname(sName), age, overallResult and a HashMap of type <String, Integer> that holds the results for subjects;

import java.util.HashMap;

public class Student {

    private String fName;
    private String sName;
    Integer age;
    Integer overallResult;
    HashMap<String, Integer> results;

    public String getfName() {
        return fName;
    }

    public void setfName(String fName) {
        this.fName = fName;
    }

    public String getsName() {
        return sName;
    }

    public void setsName(String sName) {
        this.sName = sName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getOverallResult() {
        return overallResult;
    }

    public void setOverallResult(Integer overallResult) {
        this.overallResult = overallResult;
    }

    public HashMap<String, Integer> getResults() {
        return results;
    }

    public void setResults(HashMap<String, Integer> results) {
        this.results = results;
    }
}

Our constructor might look like this;

    public Student(String fName, String sName, Integer age, Integer overallResult, HashMap<String, Integer> results) {
        this.fName = fName;
        this.sName = sName;
        this.age = age;
        this.overallResult = overallResult;
        this.results = results;
    }

We can then call our Student class somewhere else by;

HashMap<String, Integer> studentResultsHM = new HashMap<String, Integer>();
studentResultsHM.put("math",50);
studentResultsHM.put("english",70);
studentResultsHM.put("java", 90);

//creating Student
Student aStudent = new Student("john","murphy",21,100,studentResultsHM);

if we wanted to get the results of John’ exams, we might write code such as;

HashMap<String, Integer> johnsResultsHM = new HashMap<String, Integer>();
johnsResultsHM = aStudent.getResults();
System.out.println("John's Maths Result is: "+johnsResultsHM.get("math") );

Records can simplify this process somewhat. We can make a Record of Student and reduce some of the background code. For the sake of differentiation, we’ll call our record Store.

public record Store (String fName, String sName, Integer age, Integer overallResult, HashMap<String, Integer> resultsHM) {}

To create John Murphys Record, using the johnsResultsHM above, we can;

//a record 
Store johnsStore = new Store("john", "murphy",21, 100, johnsResultsHM);

And that’s it – the getter methods are done in the background along with a few other common methods that we’ll cover below. We can access data in the Record by;

System.out.println("john's surname is :"+johnsStore.sName);
System.out.println("john's overall result is: "+johnsStore.overallResult);

If we want to compare fields between another Student Record;

//Another Record
Store aNewStore = new Store("john", "murphy",21, 100, null);

//equals method
if(aNewStore.fName.equals(johnsStore.fName)){
   System.out.println("names match");
   }

There is nifty toString() method to print the record;

System.out.println("Johns Record: "+johnsStore.toString());

We can also create a constructor and specify that required fields cannot be null. In the following code, the fName and sName cannot be empty;

  public record Store (String fName, String sName, Integer age, Integer overallResult, HashMap<String, Integer> resultsHM) {
        public Store {
            Objects.requireNonNull(fName);
            Objects.requireNonNull(sName);
        }
    }

If we try to construct a new Store for Mary without her first and last name, an Exception is generated;

//This code won't work
Store marysStore =new Store(null, null, 21, 66, marysResultsHM );

But we can generate a record Store for Mary if we provide her first name and surname and nothing else:

 Store marysStore =new Store("mary", "murphy", null, null, null );
 System.out.println("Marys surname is "+ marysStore.sName+" :: Mary's overall Result: "+marysStore.overallResult);

//prints output;
Marys surname is murphy :: Mary's overall Result: null

in our previous Student Class, we might also have a HashCode checking for equality;

  @Override
    public int hashCode() {
        return Objects.hash(fName, sName);
    }

To access it, we would write;

//Getting the hashcode from the Student Class
System.out.println("johns Student Class hash is: "+aStudent.hashCode());

//outputs
johns Student Class hash is: -961526387

With Record, no need to write boilerplate code. It’s already done for us. To check if John and Mary’s Record were the same;

System.out.println("Johns Hash: "+johnsStore.hashCode() );
        System.out.println("Mary's Hash: "+marysStore.hashCode() );

        if(johnsStore.hashCode() == (marysStore.hashCode())){
            System.out.println("John and Mary match");
        }
        else{
            System.out.println("John and Mary do not match");
        }

//outputs
Johns Hash: 973504803
Mary's Hash: -34562940
John and Mary do not match

So the advantage of a JAVA Record is that there is no need to declare constructors, getters, hashcode, toString or equals. A Record will automatically generate;

  • A Constructor with the fields
  • A getter (Accessor) method
  • An equals() method that checks if all fields are the same
  • A toString() method
  • a HashCode() method that will return the same hashcode for two objects of equal value

Records have immutable data by default. That means that you cannot go and change John’s name. For example, the following code will not compile;

//Trying to change the Record field name;
johnsStore.sName="henry";

//output
cannot assign a value to final variable fName

If you have a data object with a lot of fields that will require their values to be changed often, you are better go the traditional route with a Class. You can then change john’s name with (borrowing our Student aStudent class above);

//Changing a field name in our Student Class 
aStudent.setfName("henry");

Related Posts

Java HashMap – Get highest Key or highest value

Java HashMaps are a key : value data object. They are widely used in Java and are based on the Map interface. Their flexibility lies in their ability to span…

Getting a record from HBase

Getting a record from HBase is similar to getting a record from SQL. You still need basic details like database name, table name and a row key. Where it differs…

You Missed

Global IT Outage : All eyes on CrowdStrike

  • By aCoder
  • July 19, 2024
  • 1303 views
Global IT Outage : All eyes on CrowdStrike

Java HashMap – Get highest Key or highest value

  • By aCoder
  • July 17, 2024
  • 1694 views
Java HashMap – Get highest Key or highest value

The problem with frameworks …

  • By aCoder
  • July 12, 2024
  • 1401 views
The problem with frameworks …

A.I. stocks are in bubble territory

  • By aCoder
  • July 10, 2024
  • 1254 views
A.I. stocks are in bubble territory

The AI Boyfriend

  • By aCoder
  • July 9, 2024
  • 1309 views
The AI Boyfriend

WordPress – only index page showing

  • By aCoder
  • July 2, 2024
  • 1247 views
WordPress – only index page showing