In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
Editor to share with you the example analysis of record types in Java, I believe that most people do not know much about it, so share this article for your reference, I hope you can learn a lot after reading this article, let's go to know it!
In this article, we'll see how Oracle with Java 16 formally introduces a fifth Java type in addition to classes, interfaces, enumerations, and comments: record types. Records are specific classes defined using very comprehensive syntax. They are designed to implement classes that represent data.
In particular, records are designed to represent immutable data containers. Recording syntax helps developers focus on design data without getting lost in implementation details.
Syntax
The syntax of the record is minimal:
[modifiers] record identifier (header) {[members]}
The term header refers to a comma-separated list of variable declarations that will represent the instance variables of the record. A record implicitly defines a constructor that takes the header as a parameter list, defines accessor methods for all fields declared in the header, and provides default implementations of the toString,equals and hashCode methods.
Let's look at an example right away. So suppose we are going to write an auction painting sales application. These will be understood as immutable objects. In fact, once they are sold, they cannot be changed. For example, a painting cannot change its title after it is defined. Then we can create a Painting record:
Public record Painting (String title, String author, int price) {}
We can instantiate this record as if it were a class with a constructor defined with a header argument list:
Painting painting = new Painting ("Camale ó n", "Leonardo Furino", 1000000)
Because the record also automatically defines the toString method, the following code snippet:
System.out.println (painting)
The output is generated:
Painting [title= Camale ó n, author=Leonardo Furino, price=1000000]
Therefore, one of the obvious advantages of recording is the extremely comprehensive syntax.
Records, enumerations, and classes
There are obvious similarities between record types and enumerated types. Both types replace classes in specific cases. Enumeration is designed to represent the number of constant instances of the same type defined. On the other hand, records should represent immutable data containers. Like enumerations, records simplify the work of developers by providing less verbose syntax and simple, clear rules than classes.
These records are only introduced as feature previews in Java 14 and officially released in Java 16. As usual, Java mitigates the impact of this new feature by delegating the task of converting records to classes to the compiler to maintain backward compatibility with old programs. Specifically, when enumerations are converted by the compiler to classes that extend abstract java.lang.Enum classes, records are converted by the compiler into classes that extend abstract java.lang.Record classes.
For Enum classes, the compiler will not allow developers to create classes that directly extend the Record class. In fact, it is also a special class created specifically to support the concept of records.
When we compile the Painting.java file, we get the Painting.class file. In this file, the compiler will insert a Painting class (recording the result of the conversion):
Declared final
Define a constructor that uses the header as a parameter list.
Defines the accessor methods for all fields declared in the header.
Override the Object methods: toString,equals and hashCode.
In fact, the JDK javap tool allows us to Painting.class to read the structure of the generated class through introspection using the following command:
Javap Painting.classCompiled from "Painting.java" public final class Painting extends java.lang.Record {public Painting (java.lang.String, java.lang.String, int); public java.lang.String toString (); public final int hashCode (); public final boolean equals (java.lang.Object); public java.lang.String title (); public java.lang.String author (); public int price (); Note that the accessor method identifier does not follow the usual conventions we have used so far. Instead of being called getTitle, getAuthor and getPrice they are simply called title,author and price, but the functionality remains the same.
Therefore, we can read access to each field of the record using the following syntax:
String title = painting.title (); String author = painting.author (); if the record does not exist
If we created a class whose Painting is equivalent to a record, we would have to write the following code manually:
Public final class Painting {private String title; private String author; private int price; public Painting (String title, String author, int price) {this.title = title; this.author = author; this.price = price;} public String title () {return title;} public String author () {return author;} public int price () {return price } @ Override public int hashCode () {final int prime = 31; int result = 1; result = prime * result + ((author = = null)? 0: author.hashCode ()); result = prime * result + price; result = prime * result + ((title = = null)? 0: title.hashCode ()); return result } @ Override public boolean equals (Object obj) {if (this = = obj) return true; if (obj = = null) return false; if (getClass ()! = obj.getClass () return false; Painting other = (Painting) obj; if (author = = null) {if (other.author! = null) return false } else if (! author.equals (other.author)) return false; if (price! = other.price) return false; if (title = = null) {if (other.title! = null) return false;} else if (! title.equals (other.title)) return false; return true @ Override public String toString () {return "Painting [title=" + title + ", author=" + author + ", price=" + price + "]";}}
Obviously, in this case, it is certainly more convenient to define records rather than classes, although IDE still allows us to semi-automate the development of such classes.
Inheritance and polymorphism
Records are designed to represent objects that carry immutable data. Therefore, record inheritance is not achievable. In particular, records cannot be extended because records are automatically declared final. In addition, a record cannot extend a class (obviously, it cannot extend a record) because it already extends the Record class.
This may seem like a limited choice, but it fits the concept of using records. Records must be immutable and inheritance is incompatible with immutability. However, by implicitly extending the Record class, the record inherits the methods of that class. In fact, the Record class overrides only three methods inherited from the Object class: toString, equals, and hashCode, and no new methods are defined.
In the record, we can also override the accessor methods and the three methods generated by the Object compiler at compile time. In fact, it might be useful to explicitly declare them in our code to customize and optimize them if needed. For example, we can customize the toString method Painting in the record as follows:
Public record Painting (String title, String author, int price) {@ Override public String toString () {return "The painting" + title + "by" + author + "costs" + price;}
We already know that records, like enumerations, cannot be extended, nor can other classes or records be extended. However, records can implement interfaces.
Like enumerations, records are implicit final, so abstract cannot use modifiers. So, when we implement an interface in a record, we must implement all inherited methods.
Custom record
It is not possible to declare instance variables and instance initializers in a record. This is in order not to violate the role of records, which should represent containers of immutable data.
Instead, you can declare static methods, variables, and initializers. In fact, these are static, shared by all instances of the record, and cannot access instance members of a particular object.
But the most interesting part of custom records is the ability to create constructors.
We know that if you don't add a constructor to a class, the compiler will add a constructor with no arguments, called the default constructor. When we explicitly add a constructor to a class, the compiler will no longer add the default constructor, regardless of the number of arguments.
However, in the record, the constructor that automatically adds the compiler defines the variables defined in the record header as parameters. This constructor is called a canonical constructor. Among its features, it is the only constructor that allows you to set the instance variable of the record (as we'll see soon). That is, our options for defining the constructor are as follows:
Explicitly redefine the specification constructor, preferably in its compact form.
Define an irregular constructor that calls the canonical constructor.
Standard constructor
We can explicitly declare a canonical constructor. For example, this is useful if we want to add a consistency check before setting the value of the instance variable. For example, consider the following record of an abstract photo concept to which we explicitly add a canonical constructor:
Public record Photo (String format, boolean color) {public Photo (String format, boolean color) {if (format.length () < 5) throw new IllegalArgumentException ("Format description too short"); this.format = format; this.color = color;}}
Note that initializing instance variables is necessary, otherwise the compiler will report an error. For example, if we do not initialize format variables, we will receive the following error:
Error: variable format might not have been initialized} ^ 1 error
In this case, we explicitly create a specification constructor that must define the same list of parameters defined in the record header. However, we can more easily create explicit specification constructors by using its compact form.
Compact specification constructor
It is indeed possible to create a compact specification constructor. It is characterized by not declaring a list of parameters. This does not mean that it will have an empty argument list, but that parentheses will not appear next to the identifier of the constructor. So let's rewrite a constructor that is equivalent to the previous example:
Public Photo {if (format.length () < 5) throw new IllegalArgumentException ("Format description too short");}
The use of compact specification constructors should be seen as a standard way to explicitly define constructors in records. Note that you don't even need to initialize an automatically initialized instance variable. More precisely, if we try to initialize instance variables in a compact specification constructor, we get a compile-time error.
Irregular constructor
You can also define a constructor whose parameter list is different from the canonical constructor, that is, the noncanonical constructor. In this case, we are performing a constructor overload. In fact, unlike the default constructor in a class, adding a constructor with a different argument list does not prevent the compiler from adding a canonical constructor anyway. In addition, the irregular constructor must call another constructor as its first statement. In fact, if we add the following constructor:
Public Photo (String format, boolean color, boolean msg) {if (format.length () < 5) throw new IllegalArgumentException (msg); this.format = format; this.color = color;}
We get a compile-time error:
Error: constructor is not canonical, so its first statement must invoke another constructor public Photo (String format, boolean color, String msg) {^ 1 error
Obviously, if we add another irregular constructor to call, sooner or later (explicit or implicit) the canonical constructor will be called. In our example, if we then call the canonical constructor directly, we must also delete the instruction to set the instance variable, because these will be called in the first line of the noncanonical constructor and then set by the canonical constructor. In fact, the following constructor:
Public Photo (String format, boolean color, String msg) {this (format, color); if (format.length () < 5) throw new IllegalArgumentException (msg); this.format = format; this.color = color;}
Causes the following compilation errors:
Error: variable format might already have been assigned this.format = format; ^ error: variable color might already have been assigned this.color = color; ^ 2 errors
This indicates that the two variables have been initialized at this time. This indicates that the specification constructor is always responsible for setting the instance variables of the record. So we just need to delete the unnecessary lines:
Public Photo (String format, boolean color, String msg) {this (format, color); if (format.length () < 5) throw new IllegalArgumentException (msg);}
At this point, we will be able to Photo create objects from records using both canonical and irregular constructors. For example:
Var photo1 = new Photo ("Photo 1", true); / / canonical constructorSystem.out.println (photo1); var photo2 = new Photo ("Photo 2", false, "Error!"); / / non-canonical constructorSystem.out.println (photo2); var photo3 = new Photo ("Photo", true, "Error!"); / / non-canonical constructorSystem.out.println (photo3)
The previous code will print out:
Photo [format=Photo 1, color=true] Photo [format=Photo 2, color=false] Exception in thread "main" java.lang.IllegalArgumentException: Error! At Photo. (Photo.java:8) at TestRecordConstructors.main (TestRecordConstructors.java:7) when to use records
It should be clear when to use records instead of classes. As mentioned above, records are designed to represent immutable data containers. Records cannot always be used in place of classes, especially if these classes mainly define business methods.
However, the essence of software is evolution. Therefore, even if we create a record to represent a container of immutable data, it may not be inappropriate to convert it to a class one day. One clue that should lead us to prefer to rewrite records in the form of classes is when we add too many methods or extend too many interfaces. In this case, it is worth asking if the record needs to be converted to a class.
Because of its immutable nature, recording is very suitable for sealing interfaces. In addition, it usually does not represent the concept of aggregating a large number of instance variables.
The concept of recording seems to be well suited to the implementation of a design pattern called DTO (acronym for data transfer objects).
The above is all the content of the article "sample Analysis of record types in Java". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un