使用Java 14的记录(Records)来处理只包含final字段的通用(非数据)类

huangapple go评论83阅读模式
英文:

Using Java 14 Records for generic (non-data) classes with only final fields

问题

以下是翻译好的部分:

给定一个拥有 final 字段的简单类,比如一个 String(见下面的示例)或 Spring 依赖,是否使用 Java 14 的记录(record)来使其更加简洁,并可能去除诸如 Lombok 之类的注解处理器,是一个不错的想法吗?

根据描述记录的 JEP,"记录在语义上声称是用于保存其数据的简单、透明的容器"。

显然,一个只有 final 字段的泛型类,并不完全是一个透明的数据容器,当使用记录时,它的 final 变量会被暴露出来,这可能是不希望的。然而,在许多情况下,这可能并不是一个主要问题。

因此,这是否足够被认为是对这一语言特性的"滥用"呢?或者是否存在其他不太明显的缺点?

    @RequiredArgsConstructor // 或者在不使用 Lombok 时使用显式构造函数
    class AudienceValidator implements OAuth2TokenValidator<Jwt> {
        private final String audience;
    
        public OAuth2TokenValidatorResult validate(Jwt jwt) {
            // 验证
        }
    }

    record AudienceValidator(String audience) implements OAuth2TokenValidator<Jwt> {
    
        public OAuth2TokenValidatorResult validate(Jwt jwt) {
            // 验证
        }
    }
英文:

Given a simple class with a final field, such as a String (see example below) or Spring dependencies, is a good idea to use a Java 14 record to make it more concise and possibly remove annotation processors such as Lombok?

According to the JEP describing records, "Records make the semantic claim of being simple, transparent holders for their data".

Obviously, a generic class with only final fields, is not exactly a transparent holder for its data, and when using a record, its final variables are exposed, which may not be desirable. However, in many cases it is probably not a major problem.

Therefore, is this "enough" to consider it an "abuse" of this language feature? Or are there any other, less obvious drawbacks?

@RequiredArgsConstructor // or an explicit constructor when not using lombok
class AudienceValidator implements OAuth2TokenValidator&lt;Jwt&gt; {
    private final String audience;

    public OAuth2TokenValidatorResult validate(Jwt jwt) {
        // validate
    }
}


record AudienceValidator(String audience) implements OAuth2TokenValidator&lt;Jwt&gt; {

    public OAuth2TokenValidatorResult validate(Jwt jwt) {
        // validate
    }
}

答案1

得分: 11

根据我在这里看到的情况,这取决于预期的语义,但很可能是滥用。AudienceValidator 是其状态,而且仅仅是状态吗?它的所有行为是否都源自其状态(就像 norm() 方法会源自复数的实部和虚部一样)?

最好的方式是将记录视为“名义元组”,可以通过行为进行增强。(一个有用的类比:Java 枚举与 C 枚举相对应,就像记录与结构化元组相对应。)但这似乎不是您在这里所做的,因此客户端看到这个类在API中作为记录公开,但行为不同,会感到困惑。

您可能会问:“但是,为什么我不利用这个语言功能来更轻松地编写这个类呢?” 当然,您可以随心所欲,但“阅读代码比编写代码更重要”。出于方便而故意使用错误的功能,将编写者的便利性置于读者之上。

英文:

It depends on the intended semantics here, but based on what I see here, it is probably an abuse. Is an AudienceValidator its state and nothing but its state? Does all its behavior derive from its state (the way a norm() method would derive from the real and imaginary parts of a Complex)?

The best way to think about records is they are nominal tuples, that can be enhanced with behavior. (A useful analogy: Java enums are to C enums, as records are to structural tuples.) That seems to not be what you are doing here, and so clients would be rightfully confused to see this class in an API exposed as a record, but behaving otherwise.

You might well ask "but, why wouldn't I take advantage of this language feature to make writing this class easier?" You can of course do as you like, but reading code is more important than writing code. Deliberately using the wrong feature because it's easier places the writer's convenience over that of the reader.

huangapple
  • 本文由 发表于 2020年4月10日 16:11:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/61136363.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定