如何避免枚举中出现NullPointer异常



我正在编写一个枚举,并确保该枚举不会引发nullpointer异常,因为这对使用此枚举的客户端来说很糟糕。我使用谷歌枚举,如果输入参数mood is null,它仍然抛出NPE

import com.google.common.base.Enums;
public enum KnowYourMoodEnum {
ANGRY, SAD, HAPPY, FEELING_GOOD;

private static final Set<KnowYourMoodEnum> HAPPY_MOOD_LIST = Sets.newHashSet(HAPPY, FEELING_GOOD);
private static final Set<KnowYourMoodEnum> UPSET_MOOD_LIST = Sets.newHashSet(ANGRY, SAD);

public static boolean isHappyMood(String mood) {
return HAPPY_MOOD_LIST.stream()
.anyMatch(x -> x.equals(Enums.getIfPresent(KnowYourMoodEnum.class, mood).orNull()));
}

public static boolean isUpsetMood(String mood) {
return UPSET_MOOD_LIST.stream()
.anyMatch(x -> x.equals(Enums.getIfPresent(KnowYourMoodEnum.class, mood).orNull()));
}

}

(1(对于API来说,指定";不要递给我null,否则你会得到NPE";。这在这里是有道理的。

(2( 如果不想这样做,那么if (mood == null) return false;

(3( 这是一个复杂而间接的实现。在枚举上具有属性boolean happy似乎会更简单。

使用Enums.getIfPresent似乎是多余的,将输入mood与枚举的name():进行比较(可能忽略大小写(就足够了

public static boolean isHappyMood(String mood) {
return isInSet(mood, HAPPY_MOOD_LIST);
}
public static boolean isUpsetMood(String mood) {
return isInSet(mood, UPSET_MOOD_LIST);
}

private static boolean isInSet(String mood, Set<KnowYourMoodEnum> set) {
return set.stream().anyMatch(x -> x.name().equalsIgnoreCase(mood));
}

这是空安全的,因为name()从不为空。

使用Streams并不是每个操作都会变得更好。而不是CCD_ 9只是使用了简单高效的CCD_。它更简单,而且不会执行线性搜索,而是进行高效的查找。对于这样的小集合来说,这并不是很重要,但仍然值得注意的是,Stream API不仅没有提供任何好处,反而降低了性能。

如果您希望该方法能够容忍与实际枚举常量不匹配的输入,那么首先初始化名称的Set要简单得多。

public enum KnowYourMoodEnum {
ANGRY, SAD, HAPPY, FEELING_GOOD;

private static final Set<String> HAPPY_MOOD = Stream.of(HAPPY, FEELING_GOOD)
.map(Enum::name).collect(Collectors.toSet());
private static final Set<String> UPSET_MOOD = Stream.of(ANGRY, SAD)
.map(Enum::name).collect(Collectors.toSet());
public static boolean isHappyMood(String mood) {
return HAPPY_MOOD.contains(mood);
}
public static boolean isUpsetMood(String mood) {
return UPSET_MOOD.contains(mood);
}
}

对于null或未知名称,这些方法已经计算为false

如果你想让支票不区分大小写,你可以使用

public enum KnowYourMoodEnum {
ANGRY, SAD, HAPPY, FEELING_GOOD;

private static final Set<String> HAPPY_MOOD = Stream.of(HAPPY, FEELING_GOOD)
.map(Enum::name).collect(Collectors.toCollection(
() -> new TreeSet<>(String.CASE_INSENSITIVE_ORDER)));
private static final Set<String> UPSET_MOOD = Stream.of(ANGRY, SAD)
.map(Enum::name).collect(Collectors.toCollection(
() -> new TreeSet<>(String.CASE_INSENSITIVE_ORDER)));
public static boolean isHappyMood(String mood) {
return mood != null && HAPPY_MOOD.contains(mood);
}
public static boolean isUpsetMood(String mood) {
return mood != null && UPSET_MOOD.contains(mood);
}
}

这将使用O(logn(查找而不是O(1(,但这仍然比O(n(Stream操作更好,并且仍然与此类小集合无关。此外,通过显式null检查,这些方法稍微复杂一些,但仍然比不惜一切代价引入Stream API的任何尝试简单得多。

你不需要第三方图书馆来完成这样一项简单的任务…

顺便说一句,当变量包含Set时,不要将其命名为…_LIST

最新更新