此问题是针对opensas提出的另一个问题:building a generic initializer function in java
从他的问题来看,很明显他需要从任何数据类型T1
转换为另一种类型T2
。当我在这里说“数据类型”时,我指的是仅限于通常用于表示原始数据的类型:Integer
,String
,Date
等。出于此问题的目的,我们可以考虑将原语装箱。
我想知道是否有任何API支持类型之间的转换,其中输入和输出都被推广到一组受支持的数据类型。我查看了Apache Commons' beanutils.converters package,但每个已知输入都有一个单独的转换器类。我正在寻找任何实现类似以下签名的功能:
static <IN, OUT> OUT convert(IN value, Class<OUT> targetType);
或者
static <IN, OUT> OUT convert(IN value, OUT defaultValue);
使用指向各种Commons转换器的一堆else if
块或者Map<Class<?>, Converter>
用于同一目的,实现这种映射本身并不太难。但我想知道某种功能是否得到支持。
另外,如果结果重复,我道歉。我尝试找到类似的问题,当我发现没有一个符合这种情况时,我感到很惊讶。
编辑:因此,此代码的实例示例如下:
Integer i = GenericConverter.convert("123", Integer.class); //returns 123
Date d = GenericConverter.convert(1313381772316L, Date.class); //returns today's date
Boolean b = GenericConverter.convert(0, Boolean.class); //returns false
Long l = GenericConverter.convert("asdf", Long.class); //RuntimeException
更新:我链接的BalusC代码接近标记,Bohemian的答案是一个很好的轻量级解决方案(虽然它不适用于布尔转换)。如果我们想要推广这些其他数据类型的转换,他也应该单独处理日期。我仍然希望得到更多的答案 - 特别是如果在某个地方有更多的免提API。
答案 0 :(得分:20)
我不知道任何库,但代码只是一行。
除了Date之外,所有盒装基元都有一个String construtor,所以这个方法可以解决这个问题:
public static <I, O> O convert(I input, Class<O> outputClass) throws Exception {
return input == null ? null : outputClass.getConstructor(String.class).newInstance(input.toString());
}
为了满足日期,你可以在方法中使用instanceof
,但我会推荐一个单独的方法,因为转换日期是格式和上下文敏感的东西(例如字符串) - &gt;日期解析并使用哪种格式?,长 - >日期设置时间。
我故意将错误/特殊处理留给读者作为练习。
答案 1 :(得分:12)
在JDK 8中,可以使用新的java.util.functions.Mapper
界面和lambda expression轻松实现此目标。
Mapper<String,Integer> atoi = s -> Integer.valueOf(s);
Integer r = atoi.map("10");
使用方法引用它可以更简单:
Mapper<String, Integer> atoi = Integer::new;
Integer r = atoi.map("10");
或类似的事情:
List<Long> dates = asList(1344754620310L,1344754854877L);
List<Date> asDates = dates.map(Date::new).into(new ArrayList<Date>());
或酷转换如:
List<Integer> myInts = "5,4,3,2,1,0,6,7,8,9"
.splitAsStream(",")
.map(Integer::new)
.into(new ArrayList<Integer>());
在JDK8 API的当前实现中,已经定义了一些默认映射器(即LongMapper
,IntMapper
,DoubleMapper
),并且有一个名为{{的实用程序类1}}定义其他一些像字符串映射器,身份映射器,常量映射器等
我不确定这是否是你所追求的,但当然它必须是实现它的好方法。
像您建议的那样的案例:
Mappers
可以使用static <IN, OUT> OUT convert(IN value, Class<OUT> targetType);
实用程序类实现:
Mappers
你的签名:
Mapper<String, Integer> atoi = Mappers.instantiate(String.class, Integer.class);
Integer r = atoi.map("10");
可以通过以下方式实施:
static <IN, OUT> OUT convert(IN value, OUT default);
因此,像这样的代码...
Mapper<String, Integer> atoi = chain(substitute(null, "0"), Integer::new);
Integer r = atoi.map(null); //produces 0
会产生:List<String> data = asList("0", null, "2", null, "4", null, "6");
List<Integer> myInts = data.map(chain(substitute(null, "0"), Integer::new)).into(new ArrayList<Integer>());
System.out.println(myInts);
答案 2 :(得分:2)
查看Variance,它允许您设置一个类型转换上下文,其中注册了各种转换器,然后将值移入和移出Variant类型,并由上下文处理类型转换。
Variant aVariant = Variant.of("1.2345");
double aDouble = aVariant.doubleValue();
int anInt = Variant.of("12").intValue();
String aString = Variant.of(12.0).toString();
Date aDate = Variant.of("2012-04-06").as(Date.class);
String anIsoFormattedDate = Variant.of(aDate).in(isoDateFormattingContext).toString()
答案 3 :(得分:1)
我发现BalusC的内容与我要求的内容非常接近:http://balusc.blogspot.com/2007/08/generic-object-converter.html
不幸的是,不支持任何涉及日期转换的内容,但正如评论所示,可以轻松添加更多转换方法。他的类本质上是一个很好的小框架,它使用反射在运行时收集所有转换方法,并将它们放在HashMap<String, Method>
中,其中键String
是该输入输出组合的唯一ID。
仍在寻找其他建议!特别是对于一个比我链接的代码更容易接受的API。
答案 4 :(得分:1)
如果您使用的是Spring Framework(spring-core),则可以使用class
org.springframework.core.convert.support.DefaultConversionService
默认构造函数添加了许多类型转换器,您可以通过实现Converter接口并调用addConverter(Converter)来添加自己的转换器。还有很好的unit test显示了一些转换组合。