5

我最近将 JSR305 的 RI 添加到我的项目中,并且一直在向我的接口添加注释,如下所示:

public interface AccountService
{
    @Nullable AccountResult consolidate( @Nonnull Date from, @Nonnull Date to )
}

本着 JSR 的精神(如此处所述),您是否认为我通过在接口中使用它们来滥用注释?我想指出返回值可以为 null,但我认为 @Nullable 更适用于“合并”方法。我不会将它们添加到实现中,因为当我编码时,接口的代码是我的指路明灯。

4

2 回答 2

6

您可以将“@NonNull String”视为 String 的严格子类。毕竟,任何非空字符串肯定是一个 'instanceof' '@Nullable String',但是任何 instanceof '@Nullable String' 都可能不是 '@NonNull String' 的一个实例(如果它null 就不会,例如)。

这样看,@Nullable 和@NonNull 是类型信息,因此在接口中是完全合理的。您向实现者表明他们可能返回 null,并且他们不必担心输入 null,并且您向调用者表明他们不能传入 null,并且他们应该期待 null 输出。

当然,虽然这一切都非常合理,但 vanilla javac v1.6 肯定不会像强制实际类型的类型安全那样强制执行任何这些规则。但是可以做梦,或者可以使用 pmd 或 findbugs 之类的工具来验证这些注释。

不过,@NonNull 和 @Nullable 注释对于完整的 nullity 类型系统来说是不够的。我真的不知道为什么 JSR305 没有解决这个问题,但是还有第三种类型:“@MaybeNull”。它会出现在泛型参数中;在其他任何地方,它都与@Nullable 具有相同的含义。

public static void addIfNotNull(List<@MaybeNull T> list, @Nullable T item) { if ( item != null ) list.add(item); }

如果第一个“T”上的注释是“@Nullable”,那么您不能传入非空列表,这将导致 API 相当无用。另一方面,如果是@NonNull,则不能传入一个可为空的列表。实际上,无论你在其中移动什么都没关系,它 (A) 永远不会导致 NullPointerException,并且 (B) 永远不会违反注释。所以,你需要一种表达方式:我不在乎这个特定的“T”是否可以为空;当我读取它时,我会进行空值检查,而且我永远不会写空值,所以没关系。

@MaybeNull 和 @Nullable 之间的区别类似于 '? 在泛型中扩展 Number' 和 'Number'。在泛型之外,它们的含义相同,但在泛型中存在差异。

所以,不要对很快的严格类型检查抱有希望。

@Inherited 仅适用于类,但人们会想象带注释的返回类型和带注释的参数有类似的东西。

于 2009-08-15T22:00:40.493 回答
1

我认为这取决于您添加注释的原因。

如果您只是添加它们以供参考,以便接口的实现者知道您的预期设计,那很好。

我将注解用于事务处理和安全角色实施,因此我的注解处于实现级别。这样做的好处是,我的 Spring 容器中的 AOP 处理器可以测试这个或那个注释的存在,并应用适当的代理类来执行诸如定义事务边界或确保用户被授权进行某些特定方法调用之类的事情。

因此,如果您打算将任何处理关闭注释的存在或不存在,请确保您的实现已注释。如果仅供参考,只注释接口即可。

于 2009-08-06T20:43:46.937 回答