在java中构建通用初始化函数

时间:2011-08-15 02:21:54

标签: java initialization default-value

我试图想出一个让我传入任何对象和默认值的函数,如果对象无法转换为默认值的类型,它应该返回该默认值。如果对象为null,则还应返回默认值。

它应该像这样使用:

Integer myVar = ConversionHelper.initialize( "123", 0 ) // should return Integer(123)
Integer myVar = ConversionHelper.initialize( "hello", 0 ) // should return Integer(0)

等等

我尝试使用以下代码:

public static <T> T initialize(Object o, T def) {
    T ret;

    try {
        ret = (T) o;
    } catch (Exception e) {
        ret = def;
    }

    return ret==null ? def : ret;
}

但它失败并进行基本转换,例如将Integer转换为String。

编辑:从答案中得到了许多建议,现在我正在寻找一种方法来做到这一点,而没有if ... elseif ... elseif和我的答案中出现的try catch块系列

4 个答案:

答案 0 :(得分:3)

这就是你要找的东西:

public static <T> T initialize(Object o, T def) {

    if ( o == null ) return def;

    if ( def == null ) throw new NullPointerException("Null def");

    if ( !def.getClass().isAssignableFrom(o.getClass()) ) {
        return def;
    } else {
        return (T) o;
    }

}

但是,正如您在问题中提到的那样,您无法在原始类型上使用它。您需要将它们装入对象才能使用此方法。

修改

如果null是有效选项,则:

public static <T> T initialize(Object o, T def) {

    if ( o == null ) return def;

    if ( def == null ) null;

    if ( !def.getClass().isAssignableFrom(o.getClass()) ) {
        return def;
    } else {
        return (T) o;
    }

}

如果检索返回值的属性不能保存null,则编译器会通过错误告诉您。否则,此代码将会飞行。

答案 1 :(得分:2)

通配符仅作为类型参数有效,而不是类型。在这种情况下,正如您所注意到的那样,普通的旧Object同样出色。

另一个有效的签名是:

public static <IN, OUT> OUT initialize(IN o, OUT default) { ... }

但是在你的情况下这看起来是不必要的,因为泛型类型是无界的。

至于你在try / catch中使用cast进行转换的策略,我不确定。其他人应该权衡这一部分。

编辑:正如您所发现的那样,除了最简单的数据转换之外,所有内容都非常有限。您可能需要根据in和out类型实现对相应解析方法调用的映射。

EDIT2:作为您所面临的问题的一个示例,这是有人为我正在进行的项目编写的数据转换方法:

public static <T> T mapValueString(String valueString, Class<T> targetType) {

  if (valueString == null) {
     return null;
  }
  else if(targetType.equals(String.class)) {
     return (T)valueString;
  }
  else if (targetType.equals(Date.class)) {
     return (T)MyDateTime.parseDate(valueString);
  }
  else if (targetType.equals(Timestamp.class)) {
     return (T)MyDateTime.parseTimestamp(valueString);
  }
  else if (targetType.equals(Boolean.class)) {
     String upperVal = valueString.toUpperCase();
     if (upperVal.startsWith("T")) {
        return (T)Boolean.TRUE;
     }
     else if (upperVal.startsWith("F")) {
        return (T)Boolean.FALSE;
     }
     else {
        throw new RuntimeException("Failed to parse value string into Boolean object. String was " + valueString + ".");
     }
  }
  else if (targetType.equals(Integer.class)) {
     Integer i;
     try {
        i = Integer.parseInt(valueString);
     }
     catch (NumberFormatException nfe) {
        throw new RuntimeException("Failed to parse value string into Integer object. String was " + valueString + ".", nfe);
     }
     return (T)i;
  }
  else if (targetType.equals(Long.class)) {
    Long l;
    try {
       l = Long.parseLong(valueString);
    }
    catch (NumberFormatException nfe) {
       throw new RuntimeException("Failed to parse value string into Long object. String was " + valueString + ".", nfe);
    }
    return (T)l;
  }
  else if (targetType.equals(Double.class)) {
     Double d;
     try {
        d = Double.parseDouble(valueString);
     }
     catch (NumberFormatException nfe) {
        throw new RuntimeException("Failed to parse value string into Double object. String was " + valueString + ".", nfe);
     }
     return (T)d;
  }
  else {
     throw new RuntimeException("Unsupported java type " + targetType.getName() + ".");
  }
}

请注意,这仅用于将String映射到T,您希望将T1映射到T2。有没有更好的办法?也许。 SO可以帮助您找到正确的策略吗?当然,但球会在你的球场上提出正确的问题。

EDIT3: Apache Commons' beanutils.converters可能会有所帮助。我没有尝试过,所以我不能评论它。

答案 2 :(得分:2)

public static <T> T initialize(Object o, T def) {
    T ret;

    try {
        ret = def.getClass().cast(o);
    } catch (Exception e) {
        ret = def;
    }

    return ret==null ? def : ret;
}

答案 3 :(得分:0)

非常感谢所有答案,但我遇到了以下问题

通过几个基础测试,我很快发现类型的转换能力是有限的(嘿,这里的java新手),我主要考虑将它用于基本类型(数字,字符串,日期,布尔,等)

所以我想出了以下

public static <T> T initialize(Object o, T def) {

    if (o==null) return def;

    try {
        if (def.getClass().isAssignableFrom(String.class)) {
            return (T) o.toString();
        } else if (def.getClass().isAssignableFrom(Integer.class)) {
                return (T) Integer.valueOf(o.toString());
        } else if (def.getClass().isAssignableFrom(Long.class)) {
            return (T) Long.valueOf(o.toString());
        } else if (def.getClass().isAssignableFrom(o.getClass())) {
            return (T) o;
        } else {
            return def;
        }
    } catch (Exception e) {
        return def;
    }
}

我猜我只需要在路上添加许多其他的东西......

哦,这些是我到目前为止所经历的考验......

    assertEquals("trivial case, should return the value passed",
            "hello",
            initialize("hello", "default salutation"));

    assertEquals("should return the default value",
            "default salutation",
            initialize(null, "default salutation"));

    assertEquals("should convert to the default value type",
            "123",
            initialize(123, "0"));

    assertEquals("should convert to the default value type",
            (Long) 10L, 
            initialize("10", 0L));

    assertEquals("should return default value if it can't convert to the default value type",
            (Long) 0L,
            initialize("hola", 0L));

任何更好的选择???