使用我的方法时,我可以静音警告吗?

时间:2016-07-19 02:50:55

标签: intellij-idea java-8 compiler-warnings suppress-warnings

我正在编写一个在Java中模拟?:的库方法。

  

公平地说,我不确定这是多么有用,我现在只是亲自测试一下。

/**
 * Shorthand for {@link #nullCoalescing(Object, Supplier, Object)}
 */
@NotNull
public static <RawType, BackupType> BackupType nc(
        @Nullable RawType possiblyNullValueContainer,
        @NotNull Supplier<BackupType> ifNotNull,
        @NotNull BackupType nonNullBackup) {
    return nullCoalescing(possiblyNullValueContainer, ifNotNull, nonNullBackup);
}

/**
 * Null Coalescing method: If {@code possiblyNullValueContainer} is {@code null}, {@code nonNullBackup} is returned;
 * else, {@code ifNotNull} is invoked and its result returned. The only caveat occurs when {@code
 * possiblyNullValueContainer} is a non-null {@link Optional}, wherein its {@link Optional#isPresent() isPresent()}
 * method is checked after discovering that it itself is not null.
 *
 * @param possiblyNullValueContainer The possibly-null value to check, or an {@link Optional} whose internal value
 *                                   is to be checked.
 * @param ifNotNull                  If {@code possiblyNullValueContainer} is not {@code null}, this is invoked and
 *                                   its result returned. The intended use is that this references a method that can
 *                                   be called on the aforementioned object, like {@code () ->
 *                                   possiblyNullValueContainer.toString()}. If this is {@code null}, you're just
 *                                   being silly and {@code null} will be returned.
 * @param nonNullBackup              If {@code possiblyNullValueContainer} is {@code null}, this is returned.
 * @param <RawType>                  The type of value to check for nullability
 * @param <BackupType>               The type of the backup values, which should not be null.
 *
 * @return Pretty much {@code possiblyNullValueContainer ? ifNotNull() : nonNullBackup}
 */
@NotNull
@SuppressWarnings("unchecked") // manually type-checked
public static <RawType, BackupType> BackupType nullCoalescing(
        @Nullable RawType possiblyNullValueContainer,
        @NotNull Supplier<BackupType> ifNotNull,
        @NotNull BackupType nonNullBackup) {
    if (null == possiblyNullValueContainer) {
        return nonNullBackup;
    } else if (possiblyNullValueContainer instanceof Optional) {
        // If they pass us an Optional, they must want us to check if it has a value inside rather than itself
        Optional nonNullOpt = (Optional) possiblyNullValueContainer;
        if (!nonNullOpt.isPresent()) {
            return nonNullBackup;
        }
    }

    if (null == ifNotNull) {
        Logger.getGlobal().severe("What are you doing?!");
        return null;
    } else {
        return ifNotNull.get();
    }
}

这样使用:

// kinda like int i = value ?: 0
int i = nc(value, () -> value.intValue(), 0)

// less useful, I know, but still supported
String s = nc(optional , () -> optional.get(), "simple");

哪个工作正常。当我使用完整的方法名称时会出现问题,例如:

long l = nullCoalescing(value, () -> value.longValue(), 0L)

我收到了这个警告:

Unboxing of 'nullCoalescing(value, () -> value.longValue(), 0L)' may produce 'java.lang.NullPointerException'

这显然是bubkus,因为我手动检查了该方法中的每一行,以确保在使用它时不会抛出NPE,甚至由running tests against it进行完整性检查。那么,当有人使用我的nullCoalescing方法时,如何停止显示此警告?

请注意,使用nc时,会发生这种情况(可能是因为它没有深入钻探?)。

1 个答案:

答案 0 :(得分:2)

问题源于这样一个事实:您正在捕获可空的value并无条件地在lambda表达式中调用该引用上的方法。只有在value不是null时才会评估该函数的事实对于审计工具是不可见的,因为您正在检查possiblyNullValueContainer参数,而不是捕获的值(它们包含同样的参考,但这似乎超出了审计的能力。

无论如何,我推荐不同的设计:

@NotNull
public static <RawType, BackupType> BackupType nullCoalescing(
        @Nullable RawType possiblyNullValueContainer,
        @NotNull Function<RawType,BackupType> ifNotNull,
        @NotNull BackupType nonNullBackup) {

    Objects.requireNonNull(ifNotNull);// don't provide fall-backs for illegal use
    Objects.requireNonNull(nonNullBackup); // be explicit

    if (null == possiblyNullValueContainer) {
        return nonNullBackup;
    }
    else if (possiblyNullValueContainer instanceof Optional) {
        // If they pass us an Optional,
        // they want us to check if it has a value inside rather than itself
        Optional<?> nonNullOpt = (Optional)possiblyNullValueContainer;
        if (!nonNullOpt.isPresent()) {
            return nonNullBackup;
        }
    }
    return ifNotNull.apply(possiblyNullValueContainer);
}

通过使用Function接收已针对null检查的引用,每个分析工具都应该识别lambda表达式正在访问非null值。即使是没有深入研究方法的工具也不会抱怨,就像使用它时一样

long l = nullCoalescing(value, nonNull -> nonNull.longValue(), 0L);

lambda表达式不访问捕获的可空值,而只访问lambda表达式的参数。作为奖励点,它可能更有效,因为非捕获lambda表达式将由单个实例表示,而不是在每次捕获时创建新实例(从当前实现开始)。

您甚至可以使用简化形式,例如

long l = nullCoalescing(value, nonNull -> nonNull, 0L);

long l = nullCoalescing(value, Long::longValue, 0L);

顺便说一句,上面的代码也解决了另外两个问题。通过插入单个<?>,您可以摆脱@SuppressWarnings("unchecked"),通常,通过在带有{注释的方法中记录并返回null来处理非法状态不是一个好主意。 {1}},使情况比以前更糟......