通用数据类型转换方法

Pau*_*ora 18 java generics

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

从他的问题很明显,他需要从任何数据类型转换T1为另一种类型T2.当我说"数据类型"在这里,我的意思是类型仅限于那些常用来代表原始数据:Integer,String,Date等.对于这个问题,我们可以考虑原语装箱的目的.

我想知道是否有任何API支持类型之间的转换,其中输入和输出都被推广到一组受支持的数据类型.我看了一下Apache Commons的beanutils.converters包,但每个已知输入都有一个单独的转换器类.我正在寻找任何实现类似以下签名的功能:

static <IN, OUT> OUT convert(IN value, Class<OUT> targetType);
Run Code Online (Sandbox Code Playgroud)

要不然

static <IN, OUT> OUT convert(IN value, OUT defaultValue);
Run Code Online (Sandbox Code Playgroud)

实现这种映射本身并不太难,要么使用一堆else if指向各种Commons转换器的块,要么就是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
Run Code Online (Sandbox Code Playgroud)

更新:我链接的BalusC代码接近标记,Bohemian的答案是一个很好的轻量级解决方案(虽然它不适用于布尔转换).如果我们想要推广这些其他数据类型的转换,他也应该单独处理日期.我仍然希望得到更多的答案 - 特别是如果有更多的免提API可用于某处.

Boh*_*ian 21

我不知道任何库,但代码只是一行.

除了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());
}
Run Code Online (Sandbox Code Playgroud)

为了满足日期,你可以instanceof在方法中使用,但我会推荐一个单独的方法,因为转换日期是格式和上下文敏感的东西(例如String - > Date解析并使用哪种格式?,Long - >日期设定时间).

我故意将错误/特殊处理留给读者作为练习.

  • 另外:"我故意将错误/特殊处理留给读者作为练习." 我知道你只是想把它放在一条线上:) (3认同)

Edw*_*rzo 12

JDK 8中,可以使用新java.util.functions.Mapper接口和lambda表达式轻松实现.

Mapper<String,Integer> atoi = s -> Integer.valueOf(s);
Integer r = atoi.map("10");
Run Code Online (Sandbox Code Playgroud)

使用方法引用它可以更简单:

Mapper<String, Integer> atoi = Integer::new;
Integer r = atoi.map("10");
Run Code Online (Sandbox Code Playgroud)

或者类似的事情:

List<Long> dates = asList(1344754620310L,1344754854877L);
List<Date> asDates = dates.map(Date::new).into(new ArrayList<Date>());
Run Code Online (Sandbox Code Playgroud)

或酷转换,如:

List<Integer> myInts = "5,4,3,2,1,0,6,7,8,9"
  .splitAsStream(",")
  .map(Integer::new)
  .into(new ArrayList<Integer>());
Run Code Online (Sandbox Code Playgroud)

在目前实施的JDK8 API的,一些默认的映射器已被定义(即LongMapper,IntMapper,DoubleMapper),有一个叫实用工具类Mappers,它定义了一些其他类似的字符串映射器和身份映射,恒定映射器等.

我不确定这是否是你所追求的,但当然它必须是一个很好的实现方式.

像你建议的那样的案例:

static <IN, OUT> OUT convert(IN value, Class<OUT> targetType);
Run Code Online (Sandbox Code Playgroud)

可以使用Mappers实用程序类实现:

Mapper<String, Integer> atoi = Mappers.instantiate(String.class, Integer.class);
Integer r = atoi.map("10");
Run Code Online (Sandbox Code Playgroud)

而你的签名:

static <IN, OUT> OUT convert(IN value, OUT default);
Run Code Online (Sandbox Code Playgroud)

可以通过以下方式实现:

Mapper<String, Integer> atoi = chain(substitute(null, "0"), Integer::new);
Integer r = atoi.map(null); //produces 0
Run Code Online (Sandbox Code Playgroud)

就这样,像这样的代码......

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);
Run Code Online (Sandbox Code Playgroud)

会产量: [0, 0, 2, 0, 4, 0, 6]

  • 现在是2016年,没有`java.util.functions.Mapper`但是有`java.util.function.Function` (5认同)