简体   繁体   中英

Check an replace null values in multiple variables java

I'm trying to find an easy way to perform multiple null checks/ replacements in multiple variables in Java.

I have an object with about 20 String variables. In the constructor I want to check if any of the variable values are null. If they are null I want to replace them with an empty String. I could perform a series of if statements but I feel like there must be a cleaner way to do this.

Unless you want to resort to reflection (which I strongly discourage) your best bet is probably to create a helper method ( return s == null ? "" : s ) and do

field1 = nullToEmpty(field1);
field2 = nullToEmpty(field2);
...

If you already depend on Apache Commons or Guava you can use StringUtils.defaultString or Strings.nullToEmpty .

I agree with aioobe, using reflection is something you should avoid like the plague. But if you are blessed with a project where for example you have to mock a REST interface manually and the objects that come via this interface have tons of Integer, String, Double etc. inside I think you have no other choice.

Here is a generic method that replaces all null pointers it can find in an object with its scalar default values, fills String fields with an empty string and does so recursively if the objects it finds have a parameterless default constructor. Hope this helps other people in the same situation as well.

static void fillNullObjects(Object object) {
    Field[] fields = object.getClass().getDeclaredFields();
    for (Field field : fields) {
        try {
            field.setAccessible(true);
            if (field.get(object) != null) {
                continue;
            }
            else if (field.getType().equals(Integer.class)) {
                field.set(object, 0);
            }
            else if (field.getType().equals(String.class)) {
                field.set(object, "");
            }
            else if (field.getType().equals(Boolean.class)){
                field.set(object, false);
            }
            else if (field.getType().equals(Character.class)) {
                field.set(object, '\u0000');
            }
            else if (field.getType().equals(Byte.class)) {
                field.set(object, (byte) 0);
            }
            else if (field.getType().equals(Float.class)) {
                field.set(object, 0.0f);
            }
            else if (field.getType().equals(Double.class)) {
                field.set(object, 0.0d);
            }
            else if (field.getType().equals(Short.class)) {
                field.set(object, (short) 0);
            }
            else if (field.getType().equals(Long.class)) {
                field.set(object, 0L);
            }
            else if (field.getType().getDeclaredFields().length > 0){
                for (Constructor<?> constructor : field.getClass().getConstructors()) {
                    if (constructor.getParameterTypes().length == 0) {
                        field.set(object, constructor.newInstance());
                        fillNullObjects(field.get(object));
                    }
                }
            }
       } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
public static String checkNull (String inputString){
    if(inputString == null){
         inputString = "";
    }
    return inputString;
}

And just call that whenever you want to check a string.

Store your variables in an array (or list, if you don't know exacty the number of variables but I don't think so) and loop over it

String[] variables;
//...
for(int i = 0; i < variables.length; i++)
    if(variables[i] == null) variables[i] = "";

20 field variables sounds like an egregious case. You should try to avoid explicitly handling that many variables in any situation, or at least factor the code so they are only ever explicitly listed in one place.

A common pattern is to associate each variable with an enumeration, and use the enumeration as a key in a Map with type Enum -> String, or use the enumeration's ordinal as an index into a String array that is sized to the Enumeration value.

Like so:

public enum StringProperties {
    TTL, RECVBUF, SENDBUF, RETRIES, ... ;
}

If you wanted explicit default values, you can couple an enumeration with a number of parameters:

public enum StringProperties {
    TTL ("100"), 
    RECVBUF ("1024"), 
    SENDBUF ("1500"), 
    RETRIES ("10"), 
    ... 
    ;
    public String getDefaultValue() { ... }
}

This strategy means that your code needs minimal modification if you need to add/remove a property, or change a default value.

In your (copy constructor?) case, you can loop over the enumeration values with something like:

for (StringProperties property : StringProperties.values()) {
    if (obj.getProperty(property) != null) {
        // handle present case
        ...
    } else {
        // handle default storage case
        ...
    }
}

Or, like thomas said, you can use a String array on its own, but this assumes that you don't need a way to address each String.

Check out Apache Commons' StringUtils

StringUtils.defaultString(yourString)

This replaces null s with an empty String. Or you can define your own replacement:

StringUtils.defaultString(null, "foo") // returns "foo"

http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#defaultString(java.lang.String)

For each field use the standard Java method:

Objects.toString(field, "");

Avoid constructor with a large number of fields if possible. Use Builder instead (as suggested in Effective Java, Item 2: Consider a builder when faced with many constructor parameters ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM