在JAVA中检查对象的空字段

时间:2018-09-10 16:40:25

标签: java

让我们假设我有一个对象,其中包含x个字段。允许两个非空,其余的必须为空。我不想逐字段进行空检查,所以我想知道是否存在一种使用最新Java版本某些功能进行空检查的聪明方法。

4 个答案:

答案 0 :(得分:1)

  

我不想按字段进行空检查

您可以避免自己编写支票,但是您需要在字段上“标记”约束。
为此,您可以使用Validator API(JSR 380,其中Hibernate 6 provides the default implementation)用@Null@NotNull来注释您的类字段。

并使用Validator明确验证实例。
请注意,带注释的字段在上下文中可以是必选的null,而在另一个上下文中则不一定是null。它与这种方式兼容,因为验证器仅在请求时才验证对象:即按需。


根据您的评论:

  

我正在开发一个代码库,您的解决方案具有侵入性。我会   让我接触创建该pojo的低级json解析器。一世   不想这样做

在这种情况下,您可以使用要验证的当前类外部的Map。
这将允许维护您验证的字段的名称,并在错误消息中使用它(可用于调试)。

例如:

Foo foo = new Foo();
// set foo fields...

// expected null but was not null
Map<String, Object> hasToBeNullMap = new HashMap<>();
hasToBeNullMap.put("x", foo.getX());
hasToBeNullMap.put("y", foo.getY());
hasToBeNullMap.put("z", foo.getZ());
String errrorMessageForNullExpected = getErrorFieldNames(hasToBeNullMap, Objects::nonNull);

// expected not null but was null
Map<String, Object> hasToBeNotNullMap = new HashMap<>();
hasToBeNotNullMap.put("z", foo.getZ());
String errrorMessageForNotNullExpected = getErrorFieldNames(hasToBeNotNullMap, o -> o == null);

private static String getErrorFieldNames(Map<String, Object> hasToBeNullMap, Predicate<Object> validationPred) {
    return hasToBeNullMap.entrySet()
                         .stream()
                         .filter(validationPred::test)
                         .map(Entry::getKey)
                         .collect(joining(","));
}

答案 1 :(得分:1)

您可以为POJO中的所有字段创建stream,并可以检查是否为空

return Stream.of(id, name).anyMatch(Objects::isNull);

return Stream.of(id, name).allMatch(Objects::isNull);

答案 2 :(得分:1)

如果对象中只有几个字段,并且您知道它不会经常更改,则可以根据Deadpool的回答将它们作为Stream.of自变量列出。缺点是违反了DRY原理:您在重复字段名称:一次在POJO定义中,一次在参数列表中。

如果您有很多字段(或不想重复自己),则可以使用反射:

boolean valid = Stream.of(YourPojoClass.class.getDeclaredFields())
    .filter(f -> !(f.getName().equals("fieldname allowed to be null") || f.getName.equals("the other field name")))
    .allMatch(f -> {
        f.setAccessible(true);
        try {
            return f.get(o) == null;
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    });

请注意,使用反射可能会降低性能,与解析从Web服务获得的JSON字符串相比,这可能微不足道。

如果您具有原始字段(例如intbooleanchar),并且希望将它们包括在检查中,请将它们限制为默认值(0false'\0'),然后使用以下代码:

    .allMatch(f -> {
        f.setAccessible(true);
        try {
            return (f.getType() == boolean.class && f.getBoolean(o) == false)
                    || (f.getType().isPrimitive() && f.getDouble(o) == 0)
                    || f.get(o) == null;
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    });

答案 3 :(得分:0)

您到底想何时进行检查?最好的解决方案是创建一个不可变的类,并且仅提供1个构造函数。不要添加二传手。

data