Please disable your adblock and script blockers to view this page

Java 14 Feature Spotlight: Records

Agile 2019
Preview FeaturesGiven
Java Futures
QCon New York
Java Language Architect
the Java Language
Local Variable Type Inference
Java SE
the Java Language Architect at Oracle
JSR-335 (Lambda Expressions
the Java Programming Language
Better World

Ben Hartshorne
Daniel Bryant
Greg Law
Shane Hastie
Caitlin Walker
Joe Kutner
Emily Casey
Brian Goetz
Ben Evans
Data Transfer Objects
Java 8
Java Concurrency
Jimmy Carter
Nick Evgeniev



the DevOps Toolchain


No matching tags

Positivity     39.00%   
   Negativity   61.00%
The New York Times
Write a review: Hacker News

We can declare a simple x-y point abstraction as follows:which will declare a final class called Point, with immutable components for x and y and appropriate accessors, constructors, equals, hashCode, and toString implementations.We are all familiar with the alternative - writing (or having the IDE generate) boilerplate-filled implementations of constructors, Object methods, and accessors.These are surely cumbersome to write, but more importantly, they are more work to read; we have to read through all the boilerplate code just to conclude that we didn't actually need to read it at all.A record can be best thought of as a nominal tuple; it is a transparent, shallowly immutable carrier for a specific ordered sequence of elements. Nominal means that both the aggregate and its components have names, rather than just indexes; transparent means that the state is accessible to clients (though the implementation may mediate this access); shallowly immutable means that the tuple of values represented by a record does not change once instantiated (though, if those values are references to mutable objects, the state of the referred-to objects may change).Records, like enums, are a restricted form of classes, optimized for certain common situations. We are then free to choose enums, or regular classes, based on whether the benefits of enums outweighs the costs in the specific situation at hand.Records offer us a similar bargain; what they ask us to give up is the ability to decouple the API from the representation, which in turn allows the language to derive both the API and implementation for construction, state access, equality comparison, and representation mechanically from the state description.Binding the API to the representation may seem to conflict with a fundamental object-oriented principle: encapsulation. There is nothing in this code, other than naming convention, to capture or require that these three uses of val are talking about the same thing, or that getVal() will return the most recent value set by setVal() – at best, this is captured in human-readable specification (but in reality, we almost never even do this.) Interacting with such a class is purely a leap of faith.Records, on the other hand, make a stronger commitment – that the x() accessor and the x constructor parameter are talking about the same quantity. Other than that, they can have pretty much everything other classes can: constructors, methods, static fields, type variables, interfaces, etc.In exchange for these restrictions, records automatically acquire implicit implementations of the canonical constructor (the one whose signature matches the state description), read accessors for each state component (whose names are the same as the component), private final fields for each state component, and state-based implementations of the Object methods equals(), hashCode(), and toString(). (The constructor parameters themselves are mutable, which means that constructors that want to normalize the state – such as reducing a rational to lowest terms – can do so merely by mutating the constructor parameters.) The following is the compact version of the above record declaration:This leads to a pleasing result: the only code we have to read is the code that is not mechanically derivable from the state description.While not all classes – and not even all data-centric classes – will be eligible to become records, use cases for records abound.A commonly requested feature for Java is multiple return – allowing a method to return multiple items at once; the inability to do this often leads us to exposing suboptimal APIs. Consider a pair of methods that scan a collection and return the minimal or maximal values:These methods are easy to write, but there is something unsatisfying about them; to obtain both boundary values, we have to scan the list twice. With records, we can easily temporarily attach some derived data to the contents of the stream, operate on the joined data, and then project it back to what we want:If this logic is inside a method, the record can even be declared local to the method.Of course, there are lots of other obvious cases for records as well: tree nodes, Data Transfer Objects (DTOs), messages in actor systems, etc.A common theme in the examples so far is that it was possible to get the right result without records, but we might well have been tempted to cut corners because of the syntactic overhead. Complex, ad-hoc features are harder to reason about, and are more likely to interact in surprising ways with other features – which is what we'd get if we tried to derive the feature design from the variety of JavaBean patterns commonly used today (not to mention the debates about which use cases are common enough to deserve language support).So, while it is superficially tempting to think about records as primarily being about boilerplate reduction, we preferred to approach it as a semantic problem; how can we better model data aggregates directly in the language, and provide a sound semantic basis for such classes that developers can easily reason about? (We've faced the choice between nominal and structural representation in Java before; in Java 8, we chose nominal function types over structural ones for a number of reasons; many of those same reasons apply when choosing nominal tuples over structural ones.)JEP 355 specifies records as a standalone feature, but the design of records was influenced by the desire that records work well with several other features currently under development: sealed types, pattern matching, and inline classes.Records are a form of product type, so called because their state space is (a subset of) the cartesian product of the state spaces of their components, and form one half of what are commonly called algebraic data types.

As said here by Brian Goetz