通用数据类型转换方法

这个问题是对opensas的另一个问题的回应 : 在java中构建一个通用的初始化函数

从他的问题来看,很明显他需要从任何数据类型T1转换为另一种类型T2 。 当我在这里说“数据类型”时,我的意思是类型限于通常用于表示原始数据的类型: IntegerStringDate等。出于这个问题的目的,我们可以考虑将基元装箱。

我想知道是否有任何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的当前实现中,已经定义了一些默认映射器(即LongMapperIntMapperDoubleMapper ),并且有一个名为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显示了一些转换组合。