通用数据类型转换方法
这个问题是对opensas的另一个问题的回应 : 在java中构建一个通用的初始化函数
从他的问题来看,很明显他需要从任何数据类型T1
转换为另一种类型T2
。 当我在这里说“数据类型”时,我的意思是类型限于通常用于表示原始数据的类型: Integer
, String
, Date
等。出于这个问题的目的,我们可以考虑将基元装箱。
我想知道是否有任何API支持类型之间的转换,其中输入和输出都被推广到一组受支持的数据类型。 我看了一下Apache Commons的beanutils.converters包 ,但每个已知输入都有一个单独的转换器类。 我正在寻找任何实现类似以下签名的function:
static OUT convert(IN value, Class targetType);
要不然
static OUT convert(IN value, OUT defaultValue);
实现这种映射本身并不太难,要么是使用一堆else if
块指向各种Commons转换器,要么是Map<Class, Converter>
用于相同的目的。 但我想知道某种function是否得到支持。
此外,如果这是重复,我道歉。 我尝试找到类似的问题,当我发现没有一个符合这种情况时,我很惊讶。
编辑:所以这个代码的实例将是:
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可用于某处。
在JDK 8中,可以使用新的java.util.functions.Mapper
接口和lambda表达式轻松实现。
Mapper atoi = s -> Integer.valueOf(s); Integer r = atoi.map("10");
使用方法引用可以更简单:
Mapper atoi = Integer::new; Integer r = atoi.map("10");
或者类似的事情:
List dates = asList(1344754620310L,1344754854877L); List asDates = dates.map(Date::new).into(new ArrayList ());
或酷转换,如:
List myInts = "5,4,3,2,1,0,6,7,8,9" .splitAsStream(",") .map(Integer::new) .into(new ArrayList ());
在JDK8 API的当前实现中,已经定义了一些默认映射器(即LongMapper
, IntMapper
, DoubleMapper
),并且有一个名为DoubleMapper
的实用程序类,它定义了一些其他类似的字符串映射器,身份映射器,常量映射器等。
我不确定这是否是你所追求的,但当然它必须是实现它的好方法。
像你建议的那样的案例:
static OUT convert(IN value, Class targetType);
可以使用Mappers
实用程序类实现:
Mapper atoi = Mappers.instantiate(String.class, Integer.class); Integer r = atoi.map("10");
而你的签名:
static OUT convert(IN value, OUT default);
可以通过以下方式实现:
Mapper atoi = chain(substitute(null, "0"), Integer::new); Integer r = atoi.map(null); //produces 0
就这样,像这样的代码……
List data = asList("0", null, "2", null, "4", null, "6"); List myInts = data.map(chain(substitute(null, "0"), Integer::new)).into(new ArrayList ()); System.out.println(myInts);
会产生: [0, 0, 2, 0, 4, 0, 6]
0,0,2,0,4,0,6 [0, 0, 2, 0, 4, 0, 6]
我不知道任何库,但代码只是一行。
除了Date之外,所有盒装基元都有一个String construtor,所以这个方法可以解决这个问题:
public static O convert(I input, Class outputClass) throws Exception { return input == null ? null : outputClass.getConstructor(String.class).newInstance(input.toString()); }
为了满足日期,您可以在方法中使用instanceof
,但我建议使用单独的方法,因为转换日期是格式和上下文敏感的东西(例如String – > Date解析并使用哪种格式?,Long– >日期设定时间)。
我故意将错误/特殊处理留给读者作为练习。
查看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()
转换器只是从一种类型到另一种类型的Guava 函数 ,您可以在需要时注册自己的,覆盖现有转换。
我发现BalusC的东西看起来与我要求的很接近: http : //balusc.blogspot.com/2007/08/generic-object-converter.html
遗憾的是,不支持任何涉及日期转换的内容,但正如评论所示,可以轻松添加更多转换方法。 他的类本质上是一个很好的小框架,它使用reflection在运行时收集所有转换方法并将它们放在HashMap
,其中键String
是该输入 – 输出组合的唯一ID。
还在寻找其他建议! 特别是对于一个比我链接到的代码更容易实现的API。
如果您使用的是Spring Framework(spring-core),则可以使用class
org.springframework.core.convert.support.DefaultConversionService
默认构造函数添加了许多类型转换器,您可以通过实现Converter接口并调用addConverter(Converter)来添加自己的类型。 还有一个很好的unit testing显示了一些转换组合。