Understanding Java record types

Smart code 2021-10-14 06:47:33
understanding java record types


Mention the record type , Let's first introduce the value object . Those familiar with domain driven design should have heard of the concepts of entity and value object .

The value object

Each entity has a unique identifier , It can be business ID Or assigned by the application ID. The equality of entities is entirely determined by identifiers .

A value object has no identifier , Usually used as a container for data . The equality of value objects is determined by the equality of the properties they contain .

Value objects have many application scenarios :

  • Describe the actual values in the business , For example, for name value pairs  Pair, Representing two-dimensional coordinates  Point.

  • Returns multiple values from a method . Multiple values are organized in a value object to return .

  • Parameters of the organization method . If the method has more than one parameter , You can organize these parameters into a value object , It can simplify the use of the method , It is also conducive to code refactoring .

Value objects are usually immutable . After creation, the value of the attribute will not be modified .

Use Java Represents a value object

The traditional method of representing value objects is to use ordinary Java class , The following code is the value object  GeoLocation  class .

import java.util.Objects;

public class GeoLocation {

private final double lng;
private final double lat;

public GeoLocation(double lng, double lat) {
this.lat = lat;
this.lng = lng;
}

public double getLng() {
return lng;
}

public double getLat() {
return lat;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
GeoLocation that = (GeoLocation) o;
return Double.compare(that.lng, lng) == 0
&& Double.compare(that.lat, lat) == 0;
}

@Override
public int hashCode() {
return Objects.hash(lng, lat);
}

@Override
public String toString() {
return "GeoLocation{" +
"lng=" + lng +
", lat=" + lat +
'}';
}
}

although  GeoLocation  It only includes  lng  and  lat  Two attributes , There is a lot of code to implement a complete value object class .

As you can see from the code , The class of the value object follows a certain pattern , It can be derived from properties . This includes the method of obtaining properties 、equals  and  hashCode  Method 、 as well as  toString  Such method .

Common alternatives

In order to solve this cumbersome declaration problem , There are many alternatives .

The most common solution is to use Lombok Medium  @Value  annotation , This is shown in the following code .

import lombok.Value;

@Value
public class GeoLocation {

double lng;
double lat;
}

When used  javap  see Lombok The byte code actually generated , You can see Lombok Generated relevant methods .

Compiled from "GeoLocation.java"
public final class io.vividcode.java11to17.record.lombok.GeoLocation {
public io.vividcode.java11to17.record.lombok.GeoLocation(double, double);
public double getLng();
public double getLat();
public boolean equals(java.lang.Object);
public int hashCode();
public java.lang.String toString();
}

Kotlin There are data classes in (data class), The corresponding code is as follows .

data class GeoLocation(
val lng: Double,
val lat: Double
)

Scala There are also case class, The corresponding code is as follows .

case class GeoLocation(lng: Double, lat:Double)

Basic description of record type

The type of record is Java Language native value object implementation , By keywords  record  To express . Record type in Java 14 It is introduced in the form of preview function , stay Java 15 Preview again , stay Java 16 Become a formal function in .

The following code is used as a record type  GeoLocation. attribute  lng  and  lat  Components called record types . Each record type is an aggregate of the contained components . For record types , The compiler will automatically generate the components in the class .

public record GeoLocation(double lng, double lat) {

}
  • Each component will have a corresponding  private final  Field .

  • Constructor that assigns values to all components in the record . Because the record object is immutable , All properties need to be initialized in the constructor . The constructor's parameter declaration is exactly the same as the record type's component declaration .

  • For each component , Generate methods to get values . The name of the method is consistent with the name of the component , The return value type is consistent with the component type .

  • Automatically generated  equals  and  hashCode  Method , Perform equality comparison and calculate hash value according to components .

  • Automatically generated  toString  Method , Contains the value of each component .

It can also be used  javap  View the bytecode generated by the record type , As shown below . You can see ,GeoLocation  The above method is included in the byte code of .

Compiled from "GeoLocation.java"
public final class io.vividcode.java11to17.record.record.GeoLocation extends java.lang.Record {
public io.vividcode.java11to17.record.record.GeoLocation(double, double);
public final java.lang.String toString();
public final int hashCode();
public final boolean equals(java.lang.Object);
public double lng();
public double lat();
}

Record types are declared as  final  Of , That is, they can't be inherited .

The record type is a restricted type . This is the same as enumeration types . All record types are  java.lang.Record  Subclasses of .

The above is the basic introduction of record types . Here are some advanced usage .

Advanced usage of record types

If the value of the record component needs to be verified or normalized , You can add custom constructors . such as ,GeoLocation  The value of longitude and latitude in has a range limit . You can add validation logic to the constructor , This is shown in the following code .

public record GeoLocation(double lng, double lat) {

public GeoLocation(double lng, double lat) {
if (lng <= 180 && lng >= -180) {
this.lng = lng;
} else {
throw new IllegalArgumentException("Invalid value of longitude");
}
if (lat <= 90 && lat >= -90) {
this.lat = lat;
} else {
throw new IllegalArgumentException("Invalid value of latitude");
}
}
}

The added constructor is of the same type as the automatically generated constructor . under these circumstances , The compiler will no longer generate constructors .

This form of constructor needs to initialize all components . If only some components need to be processed , You can use a compact form of constructor . In the following code , For components only  isbn  It was verified . Other uninitialized components will be automatically added with assignment operation .

public record Book(String isbn, String title, String description,
BigDecimal price) {

public Book {
if (isbn == null) {
throw new IllegalArgumentException("ISBN is invalid");
}
}
}

The above compact form of constructor , It's actually equivalent to the following code .

public record Book(String isbn, String title, String description,
BigDecimal price) {

public Book(String isbn, String title, String description, BigDecimal price) {
if (isbn == null) {
throw new IllegalArgumentException("ISBN is invalid");
}
this.isbn = isbn;
this.title = title;
this.description = description;
this.price = price;
}
}

Record types can be nested , This makes them suitable for representing complex object structures . For example, in the following code  Order  type .

public record Order(String orderId, String userId, LocalDateTime createdAt,
List<LineItem> lineItems,
Address deliveryAddress) {

public record LineItem(String productId, int quantity, BigDecimal price) {

}

public record Address(String addressLine, String cityId, String provinceId,
String zipCode) {

}
}

Record types can appear inside methods , Call it a local record (local record). The local record type is suitable for Java Flow calculation related code . If the flow calculation is complex , Local records can be used to represent intermediate calculation results , So as to improve the readability of the code .

In the following code ,calculate  Method is used to calculate the maximum order amount of each user .OrderTotal  It's a local record , Represents the amount of each order . The first flow calculates the amount of each user's order , The second calculation gives the maximum amount .

public class OrderCalculator {

public Map<String, OrderSummary> calculate(List<Order> orders) {
record OrderTotal(String orderId, BigDecimal total) {

}

Map<String, List<OrderTotal>> orderTotal = orders.stream()
.collect(
Collectors.groupingBy(Order::userId, Collectors.mapping(order -> {
BigDecimal total = order.lineItems().stream()
.map(item -> item.price()
.multiply(BigDecimal.valueOf(item.quantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
return new OrderTotal(order.orderId(), total);
}, Collectors.toList())));
return orderTotal.entrySet().stream().map(entry ->
new OrderSummary(entry.getKey(),
entry.getValue().stream()
.max(Comparator.comparing(OrderTotal::total))
.map(OrderTotal::total).orElse(BigDecimal.ZERO)))
.collect(Collectors.toMap(OrderSummary::userId, Function.identity()));
}
}

That's all for the record types .

Finally, push my new book 《Quarkus Cloud native microservice development practice 》, Interested friends are welcome to buy , Search Jingdong for the title of the book .

 picture

 Smart code
Smart code
The original of pure dry goods IT Technical articles , Gather the front and rear ends of the forefront 、 Mobile development and operation and maintenance technology
22 Original content
official account


版权声明
本文为[Smart code]所创,转载请带上原文链接,感谢
https://javamana.com/2021/10/20211002145640952e.html

  1. Hadoop Foundation - 03 - hdfs (Hadoop Distributed File System) Basic Concepts
  2. Hadoop Foundation - 05 - hdfs Project (word Frequency Statistics)
  3. Hadoop Foundation - 06 - hdfs Data Read and write
  4. The "monthly test" report card of the new car built under the lack of core: Xiaopeng and Weilai took the lead in "breaking 10000", and the ideal plummeted by 25%
  5. Introduction to making arch linux software package
  6. Hard core observation 407 HTTPS everywhere browser extension is about to retire
  7. How to use busybox on Linux
  8. In 2021, the talent incentive plan of Linux foundation open source software School Park was officially launched
  9. It's not windows or Linux. Shrink is the "God operating system"
  10. Install anydesk on Ubuntu Linux
  11. 2021, can we recommend using Linux to play games?
  12. not exist:org.springframework.kafka.listener.AbstractMessageListenerContaingetContainerProperties()
  13. Are you sure HTTPS is asymmetric encryption for content encryption? See the answers and reasons
  14. MySQL online slow log query
  15. Java JDK server installation
  16. 手把手教你使用Java开发在线生成pdf文档
  17. Questions d'entrevue dans la base de données MySQL (dernière version 2021)
  18. Java零基础小白入门必做题汇总(建议收藏)第一篇
  19. Day15 Java Foundation
  20. Day16 Java Foundation
  21. Day17 Java Foundation
  22. Day18 Java Foundation
  23. Linux installe JDK 1.8 et configure les variables d'environnement
  24. Tutoriel d'utilisation Maven super détaillé
  25. Spring boot reads project parameter configuration
  26. Docker installing rocketmq
  27. Java Zero Basic small white Beginner must make a summary of issues (recommended Collection) Chapitre 1
  28. Manuel pour vous apprendre à utiliser le développement Java pour générer des documents PDF en ligne
  29. 40 + comment les femmes s'habillent - elles pour montrer leur jeunesse?Un manteau et une jupe vous donnent un look haut de gamme tout au long de l'automne et de l'hiver
  30. Tutoriel d'installation Ubuntu 16.04 / Hadoop 3.1.3Configuration autonome / pseudo - distribuée
  31. L'apprentissage le plus détaillé de springboot à l'échelle du réseau - day01
  32. L'apprentissage le plus détaillé de springboot sur le Web - day02
  33. L'apprentissage le plus détaillé de springboot sur le Web - day03
  34. L'apprentissage le plus détaillé de springboot sur le Web - day04
  35. Tutoriel d'utilisation Maven super détaillé
  36. L'apprentissage le plus détaillé de springboot sur le Web - day05
  37. L'apprentissage le plus détaillé de springboot sur le Web - day06
  38. L'apprentissage le plus détaillé de springboot sur le Web - day07
  39. Introduction to JavaScript - write a photo album for your girlfriend
  40. [Hadoop 3. X] HDFS storage type and storage strategy (V) overview
  41. L'apprentissage le plus détaillé de springboot sur le Web - day08
  42. Introduction à la page Web de rabbitmq (3)
  43. No Converter found for return value of type: class java.util.arraylist Error Problem
  44. (16) , spring cloud stream message driven
  45. Que faut - il apprendre de l'architecture des microservices Spring Cloud?
  46. Résolution: erreur: Java: distribution cible invalide: 11problème d'erreur
  47. Springboot démarre en une minute et sort de l'enfer de la configuration SSM!
  48. Maven - un outil de gestion essentiel pour les grands projets d'usine, de l'introduction à la maîtrise![️ Collection recommandée]
  49. ️ Push to interview in Large Factory ᥧ - - Spring Boot Automatic Assembly Principle
  50. [️ springboot Template Engine] - thymeleaf
  51. Springboot - MVC Automatic configuration Principle
  52. Mybatis reverse engineering and the use of new version mybatisplus 3.4 reverse engineering
  53. Base de données MySQL - transactions et index
  54. Sécurité du printemps - [authentification, autorisation, déconnexion et contrôle des droits]
  55. Moteur de base de données InnoDB diffère de myisam
  56. Swagger - [springboot Integrated Swagger, configure Swagger, configure scan Interface, configure API Group]
  57. Cadre de sécurité Shiro - [QUICKstart, login Block, User Authentication, request Authorization]
  58. [Introduction à Java] installation de l'environnement de développement - Introduction à Java et construction de l'environnement
  59. 【 linux】 notes d'utilisation tmux
  60. MySQL + mybatis paging query - database series learning notes