Introduction
In this article, we will discuss one new feature of Java i.e introduced in Java 16. Java is amazing but there are some complaints and one of the complaints in java is very verbose, which makes java more reachable. In fact, we can know well-written java code by just reading it without documentation but there are certain places where we can think this part can be small or we are doing a small thing but we have to write a lot of lines of code just to achieve that and one example is Data Career Classes.
So once we start working with java there are several scenarios where we create classes that are actually functional basically, it will be service classes, will be service classes, utility classes, or a class that is doing basics, and then we will have some classes which are only used for data storage or for data carrying purpose.
Example: Suppose we have a client and a server and now the client says "I want data" and now if that server is java and in java, everything is an object. So even if you want to represent data that represents some object it will be an object like a product or a person or a phone. This is an object which will go from the server side to the client side.
Here, the only purpose of the class defining an object like this is to hold the data. We are not going to change data that classes are only used for data transfer. So from the server side, we will convert that into JSON so that JSON goes to the client, or maybe if you want to get data from the DB, the client needs data so the client will ask from the server, and the server will get it from the DB. Now from the DB, it will be in a row that is coming into Java as an object, and then from the object, we will get the JSON.
Here, we are focusing on the following,
- Object, and it is immutable because we don’t want to change the data.
- An object is only used for data storage we are not using extra methods.
Why and How to Implement Record
So now we will be making that object in Java and we will get to know why record comes into the picture.
So now we will create a simple class called Person class.
class Person {}
Here we want to have certain variables in this now these variables hold data we call as states. Let's have two variables as “id” and “name” and this class is used to create data this is not a functional class. We aren’t going to do any processing here. It is just to work with these variables and while working on these variables we need certain extra methods to assign values so creating two variables as private just for encapsulation and finally we don’t want to change the values.
private int id;
private String name;
Now we want a constructor by which we can assign the value for both variables.
public Person(int id, String name) {
this.id = id;
this.name = name;
}
To fetch the values we need to have the methods which will access it so we will generate getter functions,
public int getId() {
return id;
}
public String getName() {
return name;
}
Now if we want to create an object. We will directly create the object of it and with this object, we can fetch the values.
Person p1 = new Person(1, "Msft");
System.out.println(p1.getName());
System.out.println(p1.getId());
Now here will get the id and name of the object as we have functions called getName() and getId() for it.
Output
What if we want to print the entire object? If we run this code will get a hashcode i.e something like this “Person@766dd879”.
Output: Without implementing toString()
But we don’t want this so we will override one of the functions called toString() and now we run the program it will return the object with its values.
@Override
public String toString() {
return "Person{" + "id=" + id + ", name='" + name + '\'' + '}';
}
Output: With implementing toString()
Now, what if we create a new object that has the same values i.e the data inside both objects are the same but they differ in memory locations? So we can compare the two objects by comparing two objects with a equals() method of an Object class in Java.
System.out.println(p1.equals(p2))
This statement should return “TRUE” but it returns “FALSE”.
The reason they are not the same objects is that they are different objects but with the same values. We know that java doesn’t know so we can tell java when we are comparing, just comparing the values doesn’t compare memory locations. We can do it by overriding equals() and hashcode() methods.
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return id == person.id && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
And now when we run the program we will get the output “TRUE”.
The whole program can be viewed here.
class Person {
private int id;
private String name;
public Person(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Person{" + "id=" + id + ", name='" + name + '\'' + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return id == person.id && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
}
public class PersonClass {
public static void main(String[] args) {
Person p1 = new Person(1, "Msft");
Person p2 = new Person(2, "Msft");
System.out.println(p1.getName());
System.out.println(p1.getId());
System.out.println(p1);
System.out.println(p2);
System.out.println(p1.equals(p2));
}
}
Here, we can see that just to create a class that holds the data we are creating so many methods so do we have any solutions for it?
Instead of these lines of code can we use this in a single line so the answer is “YES”.
In Java, if we want to represent a class that on holds data we can create something called “RECORD”.
record Person(int id, String name) {}
This keyword ‘record’ is enough to handle above 50 lines of code. It will have the instance variables called components in case of record. Behind the scene, we will get all the objects of the above class.
Person(int id, String name) here means a parametrized constructor or a canonical constructor.
This record by default has implemented all the methods used inside the above class like getters, toString, hashcode, equals, and others method like these.
Now to confirm if we want to see this record working as above 50 lines of code, we will test it with a simple print statement.
record Person(int id, String name) {
Person p1 = new Person(1, "Msft");
Person p2 = new Person(1, "Msft");
System.out.println(p1);
System.out.println(p2);
}
Output
Here, without any toString method, we are getting the same results as we are getting by writing huge lines of code.
Summary
With this, we came to the last of this article, and we have some new learnings from this article. But before finishing, we will summarize what we learned.
What did we learn?
- What are Records?
- Why do we need Records?
- Implementation of Records.
GitHub Link: Record Classes