注释,无处不在的注释

十年前的2004年Java 1.5开始提供注释。 很难想象没有此功能的代码。 实际上,首先引入了注释,以减轻开发人员编写繁琐的样板代码的痛苦,并使代码更具可读性。 考虑一下J2EE 1.4(没有可用的注释)和Java EE5。注释的采用通过消除所有配置XML大大简化了Java EE应用程序的开发。 即使在今天,更多的注释仍被添加到最新版本的Java EE中。 这样做的目的是减轻开发人员的负担并提高生产率。 其他技术和框架也广泛使用它们。


随处注释

到处都有注释

让我们看一个有关注释如何简化代码的示例(摘自我有关JPA实体图的文章 ):

电影.java

@Entity
@Table(name = "MOVIE_ENTITY_GRAPH")
@NamedQueries({
    @NamedQuery(name = "Movie.findAll", query = "SELECT m FROM Movie m")
})
@NamedEntityGraphs({
    @NamedEntityGraph(
        name = "movieWithActors",
        attributeNodes = {
            @NamedAttributeNode("movieActors")
        }
    ),
    @NamedEntityGraph(
        name = "movieWithActorsAndAwards",
        attributeNodes = {
            @NamedAttributeNode(value = "movieActors", subgraph = "movieActorsGraph")
        },
        subgraphs = {
            @NamedSubgraph(
                    name = "movieActorsGraph",
                    attributeNodes = {
                        @NamedAttributeNode("movieActorAwards")
                    }
            )
        }
    )
})
public class Movie implements Serializable {
    @Id
    private Integer id;

    @NotNull
    @Size(max = 50)
    private String name;

    @OneToMany
    @JoinColumn(name = "ID")
    private Set<MovieActor> movieActors;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinColumn(name = "ID")
    private Set<MovieDirector> movieDirectors;

    @OneToMany
    @JoinColumn(name = "ID")
    private Set<MovieAward> movieAwards;
}

等一下! 简化吗? 真? 注释不应该使我的代码更具可读性吗? 此示例具有比实际代码更多的注释。 公平地说,我不包括获取器和设置器。 同样,某些带注释的代码可以更好地压缩,但这会使代码更难阅读。 当然,这是一个极端的情况。 无论如何,我很高兴,因为我获得了“年度注释狂”称号 。 谢谢卢卡斯!

年度注释狂

我们非常依赖注释,以至于最终滥用它们。 有趣的是,在某些情况下,批注引起了他们打算解决的相同问题。

如果?

让我们像这样重写前面的示例:

电影.java

@MovieEntity
@FindAll
@LoadWithActors
@LoadWithActorsAndAwards
public class Movie implements Serializable {
    @Id
    private Integer id;

    @Name
    private String name;

    @MovieActors
    private Set<MovieActor> movieActors;

    @MovieDirectors
    private Set<MovieDirector> movieDirectors;

    @MovieAwards
    private Set<MovieAward> movieAwards;
}

它肯定看起来更具可读性。 但是这些注释不存在。 他们来自哪里?

@LoadWithActors

LoadWithActors.java

@NamedEntityGraph(
        name = "movieWithActors",
        attributeNodes = {
                @NamedAttributeNode("movieActors")
        }
)
public @interface LoadWithActors {}

@LoadWithActorsAndAwards

LoadWithActorsAndAwards.java

@NamedEntityGraph(
        name = "movieWithActorsAndAwards",
        attributeNodes = {
                @NamedAttributeNode(value = "movieActors", subgraph = "movieActorsGraph")
        },
        subgraphs = {
                @NamedSubgraph(
                        name = "movieActorsGraph",
                        attributeNodes = {
                                @NamedAttributeNode("movieActorAwards")
                        }
                )
        }
)
public @interface LoadWithActorsAndAwards {}

其余的依次类推。 你有感觉。 这个想法是将注释元数据提取并分组到您自己的自定义注释中。 然后,您的注释可以用于表示代码中所有带注释的数据,从而更易于理解。 就像Java 8 Lambdas一样,读起来就像问题声明一样。

只是另一个例子:

WoWBusinessBean.java

@Named
@Stateless
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
@ApplicationPath("/resources")
@Path("wowauctions")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class WoWBusinessBean extends Application implements WoWBusiness {}

改写:

WoWBusinessBean.java

@RestStatelessBean("wowauctions")
public class WoWBusinessBean extends Application implements WoWBusiness {}

@RestStatelessBean

RestStatelessBean

@Named
@Stateless
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
@ApplicationPath("/resources")
@Path("#{path}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public @interface RestStatelessBean {
    String value() default "#{path}";
}

通常,我只编写一次这些注释来定义POJO的行为,而不再关注它们。 如果我可以为所有无状态休息服务重用一个注释,那将有多酷?

另一个不错的效果是,注释配置元数据没有直接绑定在代码中。 相反,它被抽象为另一个注释。 在这种情况下,有可能在编译/运行时中覆盖或替换这些值。

元注释

我最初是由David Blevins听说过这个概念的。 他在“ 元注释”中写了一篇关于这些想法的很好的文章,甚至写了一个可能的实现

为注释继承,抽象和封装提供简单的Java SE支持会很方便。 这是所有现有技术处理注释方式的重大转变。 只有每个人都开始支持这种行为才有意义。

有人可能会问,我们真的需要此功能吗? 让我们尝试权衡一些利弊:

优点

  • 简化代码。
  • 注释重用。
  • 注释配置不直接与代码绑定。 值可以被覆盖。

缺点

  • 另一层抽象。
  • 自由地创建自定义注释可以掩盖真实行为。
  • 可能会遇到某种多重继承陷阱。

结论

在可预见的将来,这种元注释不太可能在Java SE中提供。 在Java 9中,大多数焦点都放在Jigsaw中。 除了值类型和泛型专业化之外,关于Java 10的信息很少。 实际上,对于纯Java SE,所有这些注释问题都不是真正的问题。

源文件中存在的批注数量正成为有关可读性和可维护性的问题。 对于Java EE和其他类似技术尤其如此。 考虑一下HTML和CSS。 如果您正在开发HTML页面,而只需要几个CSS样式,则通常将它们内联到元素中或直接将它们包括在页面中。 如果开始使用太多样式,则可以将它们提取到外部CSS文件中,然后应用样式。 我确实认为必须通过采用元注释或其他方式来完成某些工作。 你还有其他建议吗? 请分享!

资源资源

不要忘记查看David Blevins关于Meta Annotations的帖子。 他的解释比我更好,包括技术细节。

也是带有元注释的JavaOne EJB演示文稿David Blevins讨论了这些想法。

还有什么比听大卫·布莱文斯本人更好的呢? Java EE 7,无限可扩展性遇到无限重用

翻译自: https://www.javacodegeeks.com/2014/12/annotations-annotations-everywhere.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值