Skip to content
This repository has been archived by the owner on Aug 20, 2021. It is now read-only.

全能类型转换器 ConvertUtil

feilong edited this page Nov 26, 2016 · 2 revisions

在我们日常开发工作中, 类型转换是跑不掉的,下面特别封装十分常用的方法

主要由下面几个部分组成:

ConvertUtil

1.转成数组

方法 Description
toArray(T...) 将动态数组转成数组.
toArray(Collection, Class) 将集合 collection 转成数组.
toArray(String[], Class) 将字符串数组 toBeConvertedValue 转成指定类型 targetType 的数组.

1.1 toArray(T...)

将动态数组转成数组.

示例:

 String[] array = ConvertUtil.toArray("1", "2");                  =   ["1", "2"];
 
 String[] emptyArray = ConvertUtil.<String>toArray();     =   [] ; //= new String[] {};
 Integer[] emptyArray = ConvertUtil.<Integer>toArray();   =   [] ; //= new Integer[] {};
 
 //注意
 String[] nullArray = ConvertUtil.toArray(null)                   =   null;
 ConvertUtil.toArray((String) null)                               =   new String[] { null }

注意:

  • 数组是具体化的(reified),而泛型在运行时是被擦除的(erasure)
  • 数组是在运行时才去判断数组元素的类型约束,而泛型正好相反,在运行时,泛型的类型信息是会被擦除的,只有编译的时候才会对类型进行强化。

**泛型擦除的规则: **

  • 所有参数化容器类都被擦除成非参数化的(raw type); 如 List<E>List<List<E>>都被擦除成 List

  • 所有参数化数组都被擦除成非参数化的数组;如 List<E>[],被擦除成 List[]

  • Raw type 的容器类,被擦除成其自身,如 List<E>被擦 除成 List

  • 原生类型(int,String 还有 wrapper 类)都擦除成他们的自身

  • 参数类型 E,如果没有上限,则被擦除成 Object

  • 所有约束参数如<? Extends E>、<X extends E>都被擦 除成 E

  • 如果有多个约束,擦除成第一个,如<T extends Object & E>,则擦除成 Object 这将会导致下面的代码:

      public static <K, V> Map<K, V[]> toArrayValueMap(Map<K, V> singleValueMap){
          Map<K, V[]> arrayValueMap = newLinkedHashMap(singleValueMap.size());//保证顺序和参数singleValueMap顺序相同
          for (Map.Entry<K, V> entry : singleValueMap.entrySet()){
              arrayValueMap.put(entry.getKey(), toArray(entry.getValue()));//注意此处的Value不要声明成V,否则会变成Object数组
          }
          return arrayValueMap;
      }

    调用的时候,

      Map<String, String> singleValueMap = MapUtil.newLinkedHashMap(2);
      singleValueMap.put("province", "江苏省");
      singleValueMap.put("city", "南通市");
      
      Map<String, String[]> arrayValueMap = MapUtil.toArrayValueMap(singleValueMap);
      String[] strings = arrayValueMap.get("province");//此时返回的是 Object[]

    会出现异常

      java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;

1.2 toArray(Collection, Class)

将集合 collection 转成数组.

示例:

 List<String> list = new ArrayList<>();
 list.add("xinge");
 list.add("feilong");

以前你需要写成:

 list.toArray(new String[list.size()]);

现在你只需要写成:

 String[] array = ConvertUtil.toArray(list, String.class);
 LOGGER.info(JsonUtil.format(array));

返回:

 ["xinge","feilong"]

1.3 toArray(String[], Class)

将字符串数组 toBeConvertedValue 转成指定类型 targetType 的数组.

示例:

 String[] ss = { "2", "1" };
 toArray(ss, Long.class);                                     =   new Long[] { 2L, 1L }
 
 ConvertUtil.toArray((String[]) null, Serializable.class)     =   null

2.转成List

方法 Description
toList(T...) 数组转成 (ArrayList).
toList(Collection) 将 集合 collection 转成 list.
toList(Enumeration) 将枚举 enumeration 转成 List.

2.1 toList(T...)

数组转成 (ArrayList).

说明:

  • 此方法返回的list可以进行add等操作
  • 如果直接使用Arrays#asList(Object...)返回的list没有实现 Collection#add(Object)等方法,执行list.add("c");操作的话会导致异常!
  • 而本方法使用 ArrayList.ArrayList(java.util.Collection) 来进行重新封装返回,可以执行正常的list操作

特别适合:

如果你要通过以下方式来构造list:

 List<String> list = new ArrayList<>();
 list.add("feilong1");
 list.add("feilong2");
 list.add("feilong2");
 list.add("feilong3");

此时你可以使用:

 List<String> list = toList("feilong1", "feilong2", "feilong2", "feilong3");

代码会更简洁

甚至于: 有很多时候,参数需要一个对象list,构造的时候,你需要这样

 List<UserAddress> userAddresseList = new ArrayList<>();
 UserAddress userAddress = new UserAddress();
 userAddress.setAddress("上海");
 userAddresseList.add(userAddress);

你可以重构成:

 UserAddress userAddress = new UserAddress();
 userAddress.setAddress("上海");
 List<UserAddress> userAddresseList = toList(userAddress);

2.2 toList(Collection)

将 集合 collection 转成 list.

说明:

  • 此方法很适合快速的将set转成list这样的操作

示例:

 Set<String> set = new LinkedHashSet<>();
 Collections.addAll(set, "a", "a", "b", "b");
 LOGGER.debug("{}", toList(set));

返回:

 [a,b]

2.3 toList(Enumeration)

将枚举 enumeration 转成 List.

示例:

 toList((Enumeration<String>) null) = emptyList()

3.转成Map

方法 Description
toMap(K, V) 将 key 和 value 直接转成map.
toMap(K, V, K, V) 将 key1 和 value1/key2 和 value2 直接转成map.
toMap(Map<K, V>, Class, Class) 将诸如 Map<String, String> 类型转成 Map<Integer, Integer> 类型.
toMap(Map<K, V>, Transformer<K, I>, Transformer<V, J>) 将诸如 Map<String, String> 类型转成 Map<Integer, Integer> 类型.
toMap(Properties) 将 properties 转换成map.
toMap(Collection) 将 mapEntryCollection 转成map (LinkedHashMap).
toMapUseEntrys(Entry<K, V>...) 将 java.util.Map.Entry数组转成map (LinkedHashMap).

3.1 toMap(K, V)

将 key 和 value 直接转成map.

说明:

  • 返回是的是 LinkedHashMap

  • 非常适合单key的场景,比如

      Map<String, String> paramMap = new HashMap<>();
      paramMap.put("name", "jinxin");
      request.setParamMap(paramMap);

    上面的3行代码可以重写成

      request.setParamMap(toMap("name", "jinxin"));

    一行代码就搞定了,很简洁,有木有~~

    示例:

      LOGGER.debug(JsonUtil.format(ConvertUtil.toMap("张飞", "丈八蛇矛")));

    返回:

      {"张飞": "丈八蛇矛"}

重构: 对于以下代码:

 private List<ShopCommand> loadShopCommandList(){
     Map<String, Object> paraMap = new HashMap<>();
     paraMap.put("orgTypeId", OrgType.ID_SHOP_TYPE);
 
     return shopCommandDao.findShopListByOrgaTypeId(paraMap);
 }

可以重构成:

 private List<ShopCommand> loadShopCommandList(){
     return shopCommandDao.findShopListByOrgaTypeId(ConvertUtil.toMap("orgTypeId", (Object) OrgType.ID_SHOP_TYPE));
 }

3.2 toMap(K, V, K, V)

将 key1 和 value1/key2 和 value2 直接转成map.

说明:

  • 返回是的是 LinkedHashMap

  • 非常适合2个key的场景,比如

      Map<String, String> paramMap = new HashMap<>();
      paramMap.put("name", "jinxin");
      paramMap.put("age", "18");
      request.setParamMap(paramMap);

    上面的3行代码可以重写成

      request.setParamMap(toMap("name", "jinxin", "age", "18"));

    一行代码就搞定了,很简洁,有木有~~

重构: 对于以下代码:

 Map<String, Long> map = new HashMap<>();
 map.put("itemId", itemId);
 map.put("memberId", memberId);
 memberFavoritesDao.findMemberFavoritesByMemberIdAndItemId(map);

可以重构成:

 Map<String, Long> map = ConvertUtil.toMap("itemId", itemId, "memberId", memberId);
 memberFavoritesDao.findMemberFavoritesByMemberIdAndItemId(map);

3.3 toMap(Map<K, V>, Class, Class)

将诸如 Map<String, String> 类型转成 Map<Integer, Integer> 类型.

说明:

  • 适合只是简单的将key value类型转换,而不需要自己再构建Transformer,再去调用 toMap(Map, Transformer, Transformer) ,简化操作
  • 返回的是 LinkedHashMap,顺序依照入参 inputMap
  • 返回的是新的map,原来的toMap参数不受影响
  • 也支持诸如 Map<String, Integer>Map<Integer, String> (key和value 使用不同的转换器)
  • 也支持诸如 Map<String, String>Map<Integer, Integer[]> (单值转数组)
  • 也支持诸如 Map<String[], String[]>Map<Integer[], Long[]> (数组转数组)

示例: 场景1:Map<String, String>Map<Integer, Integer> 类型

 Map<String, String> map = toMap("1", "2");
 Map<Integer, Integer> returnMap = toMap(map, Integer.class, Integer.class);
 
 // 输出测试
 for (Map.Entry<Integer, Integer> entry : returnMap.entrySet()){
     Integer key = entry.getKey();
     Integer value = entry.getValue();
     LOGGER.debug("key:[{}],value:[{}]", key, value);
 }

返回:

 key:[1],value:[2]

场景2: Map<String, String> 转 Map<Integer, Integer[]>

 Map<String, String> map = toMap("1", "2,2");
 
 //key和value转成不同的类型
 Map<Integer, Integer[]> returnMap = toMap(map, Integer.class, Integer[].class);
 
 // 输出测试
 for (Map.Entry<Integer, Integer[]> entry : returnMap.entrySet()){
     Integer key = entry.getKey();
     Integer[] value = entry.getValue();
 
     LOGGER.debug("key:[{}],value:[{}]", key, value);
 }

返回:

 key:[1],value:[[2, 2]]

场景3: Map<String[], String[]> 转 Map<Integer[], Long[]>

 Map<String[], String[]> map = toMap(toArray("1"), toArray("2", "8"));
 
 //key和value转成不同的类型
 Map<Integer[], Long[]> returnMap = toMap(map, Integer[].class, Long[].class);
 
 assertThat(returnMap, allOf(hasEntry(toArray(1), toArray(2L, 8L))));

3.4 toMap(Map<K, V>, Transformer<K, I>, Transformer<V, J>)

将诸如 Map<String, String> 类型转成 Map<Integer, Integer> 类型.

说明:

  • 适合复杂的类型转换场景,如果只是简单的类型转换,你可以直接调用 toMap(Map, Class, Class)
  • 返回的是 LinkedHashMap,顺序依照入参 inputMap
  • 返回的是新的map,原来的toMap参数不受影响
  • 也支持诸如 Map<String, Integer> 转 Map<Integer, String> (key和value 使用不同的转换器)
  • 也支持诸如 Map<String, String> 转 Map<Integer, Integer[]> (单值转数组)
  • 也支持诸如 Map<String[], String[]> 转 Map<Integer[], Long[]> (数组转数组)

示例: **场景1: **将Map<String, String> 转 Map<Integer, Integer> 类型

 Map<String, String> map = toMap("1", "2");
 
 //key和value 都转成integer 使用相同的转换器
 Transformer<String, Integer> transformer = new SimpleClassTransformer<>(Integer.class);
 
 Map<Integer, Integer> returnMap = toMap(map, transformer, transformer);
 
 // 输出测试
 for (Map.Entry<Integer, Integer> entry : returnMap.entrySet()){
     Integer key = entry.getKey();
     Integer value = entry.getValue();
     LOGGER.debug("key:[{}],value:[{}]", key, value);
 }

返回:

 key:[1],value:[2]

场景2: Map<String, String> 转 Map<Integer, Integer[]>

 Map<String, String> map = toMap("1", "2,2");
 
 Transformer<String, Integer> keyTransformer = new SimpleClassTransformer<>(Integer.class);
 Transformer<String, Integer[]> valueTransformer = new SimpleClassTransformer<>(Integer[].class);
 
 //key和value转成不同的类型
 Map<Integer, Integer[]> returnMap = toMap(map, keyTransformer, valueTransformer);
 
 // 输出测试
 for (Map.Entry<Integer, Integer[]> entry : returnMap.entrySet()){
     Integer key = entry.getKey();
     Integer[] value = entry.getValue();
 
     LOGGER.debug("key:[{}],value:[{}]", key, value);
 }

返回:

 key:[1],value:[[2, 2]]

场景3: Map<String[], String[]> 转 Map<Integer[], Long[]>

 Map<String[], String[]> map = toMap(toArray("1"), toArray("2", "8"));
 
 Transformer<String[], Integer[]> keyTransformer = new SimpleClassTransformer<>(Integer[].class);
 Transformer<String[], Long[]> valueTransformer = new SimpleClassTransformer<>(Long[].class);
 
 //key和value转成不同的类型
 Map<Integer[], Long[]> returnMap = toMap(map, keyTransformer, valueTransformer);
 
 assertThat(returnMap, allOf(hasEntry(toArray(1), toArray(2L, 8L))));

3.5 toMap(Properties)

将 properties 转换成map.

示例:

 Properties properties = new Properties();
 
 properties.setProperty("name", "feilong");
 properties.setProperty("age", "18");
 properties.setProperty("country", "china");
 
 LOGGER.debug(JsonUtil.format(toMap(properties)));

返回:

 {
 "age": "18",
 "country": "china",
 "name": "feilong"
 }

说明:

  • 返回的map 经过了 SortUtil.sortMapByKeyAsc(Map)排序处理,方便输出日志

3.6 toMapUseEntrys(Entry<K, V>...)

将 java.util.Map.Entry数组转成map (LinkedHashMap).

说明:

  • 返回是的是 LinkedHashMap,顺序依照参数 java.util.Map.Entry数组顺序,key是 java.util.Map.Entry.getKey(),value 是 java.util.Map.Entry.getValue()

  • java.util.Map.Entry 已知实现类,你可以使用 Pair,或者 java.util.AbstractMap.SimpleEntry

    Pair 示例:

      Map<String, String> map = ConvertUtil.toMapUseEntrys(
                      Pair.of("张飞", "丈八蛇矛"),
                      Pair.of("关羽", "青龙偃月刀"),
                      Pair.of("赵云", "龙胆枪"),
                      Pair.of("刘备", "双股剑"));
      LOGGER.debug(JsonUtil.format(map));

    返回:

      {
      "张飞": "丈八蛇矛",
      "关羽": "青龙偃月刀",
      "赵云": "龙胆枪",
      "刘备": "双股剑"
      }

    java.util.AbstractMap.SimpleEntry 示例:

      Map<String, String> map = ConvertUtil.toMapUseEntrys(
                      new SimpleEntry<>("张飞", "丈八蛇矛"),
                      new SimpleEntry<>("关羽", "青龙偃月刀"),
                      new SimpleEntry<>("赵云", "龙胆枪"),
                      new SimpleEntry<>("刘备", "双股剑"));
      LOGGER.debug(JsonUtil.format(map));
      

    返回:

      {
      "张飞": "丈八蛇矛",
      "关羽": "青龙偃月刀",
      "赵云": "龙胆枪",
      "刘备": "双股剑"
      }

重构: 以前初始化全局map的时候,你可能会这么写

 // 除数和单位的map,必须是有顺序的 从大到小.
 private static final Map<Long, String> DIVISOR_AND_UNIT_MAP = new LinkedHashMap<>();
 
 static{
     DIVISOR_AND_UNIT_MAP.put(FileUtils.ONE_TB, "TB");//(Terabyte,太字节,或百万兆字节)=1024GB,其中1024=2^10(2的10次方)
     DIVISOR_AND_UNIT_MAP.put(FileUtils.ONE_GB, "GB");//(Gigabyte,吉字节,又称“千兆”)=1024MB
     DIVISOR_AND_UNIT_MAP.put(FileUtils.ONE_MB, "MB");//(Megabyte,兆字节,简称“兆”)=1024KB
     DIVISOR_AND_UNIT_MAP.put(FileUtils.ONE_KB, "KB");//(Kilobyte 千字节)=1024B
 }

现在你可以重构成:

 
 // 除数和单位的map,必须是有顺序的 从大到小.
 private static final Map<Long, String> DIVISOR_AND_UNIT_MAP = ConvertUtil.toMapUseEntrys(
                 Pair.of(FileUtils.ONE_TB, "TB"), //(Terabyte,太字节,或百万兆字节)=1024GB,其中1024=2^10(2的10次方) 
                 Pair.of(FileUtils.ONE_GB, "GB"), //(Gigabyte,吉字节,又称“千兆”)=1024MB
                 Pair.of(FileUtils.ONE_MB, "MB"), //(Megabyte,兆字节,简称“兆”)=1024KB
                 Pair.of(FileUtils.ONE_KB, "KB")); //(Kilobyte 千字节)=1024B

代码更加简洁

3.7 toMap(Collection)

将 mapEntryCollection 转成map (LinkedHashMap).

说明:

  • 返回是的是 LinkedHashMap,顺序依照参数 mapEntryCollection,key是 java.util.Map.Entry.getKey(),value 是 java.util.Map.Entry.getValue()

  • java.util.Map.Entry 已知实现类,你可以使用 Pair,或者 java.util.AbstractMap.SimpleEntry

    Pair 示例:

      Map<String, String> map = toMap(toList(//
                      Pair.of("张飞", "丈八蛇矛"),
                      Pair.of("关羽", "青龙偃月刀"),
                      Pair.of("赵云", "龙胆枪"),
                      Pair.of("刘备", "双股剑")));
      LOGGER.debug(JsonUtil.format(map));
     

    返回:

      {
      "张飞": "丈八蛇矛",
      "关羽": "青龙偃月刀",
      "赵云": "龙胆枪",
      "刘备": "双股剑"
      }
      

    java.util.AbstractMap.SimpleEntry 示例:

      Map<String, String> map = ConvertUtil.toMap(
                      toList(
                                      new SimpleEntry<>("张飞", "丈八蛇矛"),
                                      new SimpleEntry<>("关羽", "青龙偃月刀"),
                                      new SimpleEntry<>("赵云", "龙胆枪"),
                                      new SimpleEntry<>("刘备", "双股剑")));
      LOGGER.debug(JsonUtil.format(map));
     

    返回:

      {
      "张飞": "丈八蛇矛",
      "关羽": "青龙偃月刀",
      "赵云": "龙胆枪",
      "刘备": "双股剑"
      }

4.转成常用类型

方法 Description
toInteger(Object) 将 toBeConvertedValue 转换成 Integer类型.
toInteger(Object, Integer) 将 toBeConvertedValue 转换成 Integer类型,如果转换不了返回默认值 defaultValue.
toIntegers(Object) 将 toBeConvertedValue 转成Integer 数组.
toBoolean(Object) 将 toBeConvertedValue 转换成 Boolean类型.
toLong(Object) 将 toBeConvertedValue 转换成 Long类型.
toLongs(Object) 将 toBeConvertedValue 转成Long 数组.
toBigDecimal(Object) 将 toBeConvertedValue 转换成 java.math.BigDecimal.

4.1 toInteger(Object)

将 toBeConvertedValue 转换成 Integer类型.

示例:

 ConvertUtil.toInteger(null)                  = null
 ConvertUtil.toInteger("aaaa")                = null
 ConvertUtil.toInteger(8L)                    = 8
 ConvertUtil.toInteger("8")                   = 8
 ConvertUtil.toInteger(new BigDecimal("8"))   = 8

如果传入的参数 toBeConvertedValue 是 数组,那么取第一个元素进行转换,参见 AbstractConverter.convertArray(Object) L227:

 ConvertUtil.toInteger(new String[] { "1", "2", "3" }) = 1

如果传入的参数 toBeConvertedValue 是 集合,那么取第一个元素进行转换,参见 AbstractConverter.convertArray(Object) Line234:

 ConvertUtil.toInteger(toList("1", "2")) = 1

该方法非常适用 获取request请求的分页参数

示例: 原来的写法:

 public static Integer getCurrentPageNo(HttpServletRequest request,String pageParamName){
     String pageNoString = RequestUtil.getParameter(request, pageParamName);
     try{
         int pageNo = Integer.parseInt(pageNoString);
         return pageNo;
     }catch (Exception e){
         LOGGER.error(e.getClass().getName(), e);
     }
     return 1; // 不带这个参数或者转换异常返回1
 }

现在可以更改成:

 public static Integer getCurrentPageNo(HttpServletRequest request,String pageParamName){
     String pageNoString = RequestUtil.getParameter(request, pageParamName);
     Integer pageNo = ConvertUtil.toInteger(pageNoString);
     return null == pageNo ? 1 : pageNo;
 }

当然对于这种场景,最快捷的:调用支持默认值的 toInteger(Object, Integer) 方法

 public static Integer getCurrentPageNo(HttpServletRequest request,String pageParamName){
     String pageNoString = RequestUtil.getParameter(request, pageParamName);
     return ConvertUtil.toInteger(pageNoString, 1);
 }
 

4.2 toInteger(Object, Integer)

将 toBeConvertedValue 转换成 Integer类型,如果转换不了返回默认值 defaultValue.

示例:

 ConvertUtil.toInteger(null,null)               = null
 ConvertUtil.toInteger(null,1)                  = 1
 ConvertUtil.toInteger("aaaa",1)                = 1
 ConvertUtil.toInteger(8L,1)                    = 8
 ConvertUtil.toInteger("8",1)                   = 8
 ConvertUtil.toInteger(new BigDecimal("8"),1)   = 8

如果传入的参数 toBeConvertedValue 是 数组,那么取第一个元素进行转换,参见 AbstractConverter.convertArray(Object) L227:

 ConvertUtil.toInteger(new String[] { "1", "2", "3" }, 8) = 1

如果传入的参数 toBeConvertedValue 是 集合,那么取第一个元素进行转换,参见 AbstractConverter.convertArray(Object) Line234:

 ConvertUtil.toInteger(toList("1", "2"), 8) = 1

该方法非常适用 获取request请求的分页参数

示例: 原来的写法:

 public static Integer getCurrentPageNo(HttpServletRequest request,String pageParamName){
     String pageNoString = RequestUtil.getParameter(request, pageParamName);
     try{
         int pageNo = Integer.parseInt(pageNoString);
         return pageNo;
     }catch (Exception e){
         LOGGER.error(e.getClass().getName(), e);
     }
     return 1; // 不带这个参数或者转换异常返回1
 }

现在可以更改成:

 public static Integer getCurrentPageNo(HttpServletRequest request,String pageParamName){
     String pageNoString = RequestUtil.getParameter(request, pageParamName);
     return ConvertUtil.toInteger(pageNoString, 1);
 }

4.3 toIntegers(Object)

toBeConvertedValue 转成Integer 数组.

说明:

  • 核心实现,参见 ArrayConverter.convertToType(Class, Object)
  • 如果参数 toBeConvertedValue是 数组 或者 Collection ,参见ArrayConverter#convertToType(Class,Object),会构造一个Integer数组,长度就是 toBeConvertedValue的大小或者长度,然后迭代toBeConvertedValue依次逐个进行转换

示例:

 ConvertUtil.toIntegers(new String[] { "1", "2", "3" })       = [1,2,3]
 ConvertUtil.toIntegers(toList("1", "2", "3"))    = [1,2,3]

如果参数 toBeConvertedValue不是数组也不是Collection 那么首先会调用 ArrayConverter.convertToCollection(Class, Object) 将 toBeConvertedValue转成集合,转换逻辑参见 ArrayConverter.convertToCollection(Class, Object):

如果 toBeConvertedValue是Number, Boolean 或者 java.util.Date ,那么构造只有一个 toBeConvertedValue 元素的 List返回. 其他类型将转成字符串,然后调用 ArrayConverter.parseElements(Class, String)转成list. 具体转换逻辑为:

字符串期望是一个逗号分隔的字符串. 字符串可以被'{' 开头 和 '}'结尾的分隔符包裹,程序内部会自动截取. 会去除前后空白. Elements in the list may be delimited by single or double quotes. Within a quoted elements, the normal Java escape sequences are valid. 得到list之后,会构造一个Integer数组,长度就是 toBeConvertedValue的大小或者长度,然后迭代toBeConvertedValue依次逐个进行转换

示例:

 ConvertUtil.toIntegers("1,2,3")                  = new Integer[] { 1, 2, 3 }
 ConvertUtil.toIntegers("{1,2,3}")                = new Integer[] { 1, 2, 3 }
 ConvertUtil.toIntegers("{ 1 ,2,3}")              = new Integer[] { 1, 2, 3 }
 ConvertUtil.toIntegers("1,2, 3")                 = new Integer[] { 1, 2, 3 }
 ConvertUtil.toIntegers("1,2 , 3")                = new Integer[] { 1, 2, 3 }

每个元素转换成 Integer的时候,会调用 org.apache.commons.beanutils.converters.NumberConverter.convertToType(Class, Object),具体的规则是:

1.如果 元素是 Number类型 那么会调用 org.apache.commons.beanutils.converters.NumberConverter.toNumber(Class, Class, Number) 2.如果 元素是 Boolean类型 那么 true被转成1,false 转成 0 3.其他情况 将元素转成字符串,并trim,再进行转换 4.元素是null的情况 如果有元素是null,那么会调用 org.apache.commons.beanutils.converters.AbstractConverter.convert(Class, Object),会调用 org.apache.commons.beanutils.converters.AbstractConverter.handleMissing(Class) 方法,没有默认值的话,会抛出异常,然后catch之后返回 empty Integer 数组 示例:

 ConvertUtil.toIntegers(toList("1", "2", " 3"))        = new Integer[] { 1, 2, 3 }
 ConvertUtil.toIntegers(toArray(true, false, false))                                  = new Integer[] { 1, 0, 0 }
 ConvertUtil.toIntegers(new String[] { "1", null, "2", "3" })   

4.4 toBoolean(Object)

toBeConvertedValue 转换成 Boolean类型.

示例:

 
 ConvertUtil.toBoolean(null)      =   null
 
 ConvertUtil.toBoolean(1L)        =   true
 ConvertUtil.toBoolean("1")       =   true
 ConvertUtil.toBoolean("9")       =   false
 ConvertUtil.toBoolean("1,2,3")   =   false

逻辑及规则:

  • 如果 "true", "yes", "y", "on", "1", 返回 true
  • 如果 "false", "no", "n", "off", "0", 返回 false
  • 其他抛出 conversionException, 但是在 handleError(Class, Object, Throwable) 方法里面返回默认值, BooleanConverter 的默认值,参见 registerStandard(boolean, boolean)
  • 你也可以调用 BooleanConverter(String[], String[], Object) 设置 trueStrings 和 falseStrings

和 Boolean.parseBoolean(String)的区别:

  • Boolean.parseBoolean(String),仅当 (String != null) 并且 String.equalsIgnoreCase("true") 返回 true

4.5 toLong(Object)

toBeConvertedValue 转换成 Long类型.

示例:

 ConvertUtil.toLong(null)                     = null
 ConvertUtil.toLong("aaaa")                   = null
 ConvertUtil.toLong(8)                        = 8L
 ConvertUtil.toLong("8")                      = 8L
 ConvertUtil.toLong(new BigDecimal("8"))      = 8L

如果传入的参数 toBeConvertedValue 是 数组,那么取第一个元素进行转换,参见 AbstractConverter.convertArray(Object) L227:

 ConvertUtil.toLong(new String[] { "1", "2", "3" }) = 1L

如果传入的参数 toBeConvertedValue 是 集合,那么取第一个元素进行转换,参见 AbstractConverter.convertArray(Object) Line234:

 ConvertUtil.toLong(toList("1", "2")) = 1L

4.6 toLongs(Object)

将 toBeConvertedValue 转成Long 数组.

说明: 核心实现,参见 ArrayConverter.convertToType(Class, Object)

如果参数 toBeConvertedValue 是 数组 或者 Collection 参见ArrayConverter#convertToType(Class,Object) 会构造一个Long数组,长度就是 toBeConvertedValue的大小或者长度,然后迭代toBeConvertedValue依次逐个进行转换

示例:

 ConvertUtil.toLongs(new String[] { "1", "2", "3" }       = [1L,2L,3L]
 ConvertUtil.toLongs(toList("1", "2", "3"))               = [1L,2L,3L]

如果参数 toBeConvertedValue不是数组也不是Collection 那么首先会调用 ArrayConverter.convertToCollection(Class, Object) 将 toBeConvertedValue转成集合,转换逻辑参见 ArrayConverter.convertToCollection(Class, Object):

如果 toBeConvertedValue是Number, Boolean 或者 java.util.Date ,那么构造只有一个 toBeConvertedValue 元素的 List返回. 其他类型将转成字符串,然后调用 ArrayConverter.parseElements(Class, String)转成list. 具体转换逻辑为:

字符串期望是一个逗号分隔的字符串. 字符串可以被'{' 开头 和 '}'结尾的分隔符包裹,程序内部会自动截取. 会去除前后空白. Elements in the list may be delimited by single or double quotes. Within a quoted elements, the normal Java escape sequences are valid. 得到list之后,会构造一个Long数组,长度就是 toBeConvertedValue的大小或者长度,然后迭代toBeConvertedValue依次逐个进行转换

示例:

 ConvertUtil.toLongs("1,2,3")                  = new Long[] { 1L, 2L, 3L }
 ConvertUtil.toLongs("{1,2,3}")                = new Long[] { 1L, 2L, 3L }
 ConvertUtil.toLongs("{ 1 ,2,3}")              = new Long[] { 1L, 2L, 3L }
 ConvertUtil.toLongs("1,2, 3")                 = new Long[] { 1L, 2L, 3L }
 ConvertUtil.toLongs("1,2 , 3")                = new Long[] { 1L, 2L, 3L }

每个元素转换成 Integer的时候,会调用 org.apache.commons.beanutils.converters.NumberConverter.convertToType(Class, Object),具体的规则是:

1.如果 元素是 Number类型 那么会调用 org.apache.commons.beanutils.converters.NumberConverter.toNumber(Class, Class, Number) 2.如果 元素是 Boolean类型 那么 true被转成1L,false 转成 0L 3.其他情况 将元素转成字符串,并trim,再进行转换 4.元素是null的情况 如果有元素是null,那么会调用 org.apache.commons.beanutils.converters.AbstractConverter.convert(Class, Object),会调用 org.apache.commons.beanutils.converters.AbstractConverter.handleMissing(Class) 方法,没有默认值的话,会抛出异常,然后catch之后返回 empty Integer 数组 示例:

 ConvertUtil.toLongs(toList("1", "2", " 3"))        = new Long[] { 1L, 2L, 3L }
 ConvertUtil.toLongs(toArray(true, false, false))                                  = new Long[] { 1L, 0L, 0L }
 ConvertUtil.toLongs(new String[] { "1", null, "2", "3" })                         = new Long[] {}

特别适合以下形式的代码:

 protected long[] getOrderIdLongs(String orderIds){
     // 确认交易时候插入数据库的时候,不应该会出现空的情况
     String[] orderIdArray = orderIds.split(",");
     int orderLength = orderIdArray.length;
     long[] ids = new long[orderLength];
     for (int i = 0, j = orderLength; i < j; ++i){
         ids[i] = Long.parseLong(orderIdArray[i]);
     }
     return ids;
 }

可以重构成:

 protected long[] getOrderIdLongs(String orderIds){
     return toLongs(orderIds);
 }

4.7 toBigDecimal(Object)

将 toBeConvertedValue 转换成 java.math.BigDecimal.

示例:

 ConvertUtil.toBigDecimal(null)                     = null
 ConvertUtil.toBigDecimal("aaaa")                   = null
 ConvertUtil.toBigDecimal(8)                        = BigDecimal.valueOf(8)
 ConvertUtil.toBigDecimal("8")                      = BigDecimal.valueOf(8)
 ConvertUtil.toBigDecimal(new BigDecimal("8"))      = BigDecimal.valueOf(8)

如果传入的参数 toBeConvertedValue 是 数组,那么取第一个元素进行转换,参见 AbstractConverter.convertArray(Object) L227:

 ConvertUtil.toBigDecimal(new String[] { "1", "2", "3" }) = BigDecimal.valueOf(1)

如果传入的参数 toBeConvertedValue 是 集合,那么取第一个元素进行转换,参见 AbstractConverter.convertArray(Object) Line234:

 ConvertUtil.toBigDecimal(toList("1", "2")) = BigDecimal.valueOf(1)

java.lang.Double 转成 java.math.BigDecimal注意点:

  • 推荐使用 BigDecimal.valueOf(double),不建议使用 new BigDecimal(double),参见 JDK API
    • new BigDecimal(0.1) ====> 0.1000000000000000055511151231257827021181583404541015625
    • BigDecimal.valueOf(0.1) ====> 0.1
  • 本方法底层调用的是 NumberConverter#toNumber(Class, Class, Number),正确的处理了 java.lang.Double 转成 java.math.BigDecimal

5.转成字符串

方法 Description
toString(Object) 把对象 toBeConvertedValue 转换成字符串.
toString(Object[], ToStringConfig) 将数组 arrays 通过ToStringConfig 拼接成字符串.
toString(Collection<?>, ToStringConfig) 将集合 collection 使用拼接配置 toStringConfig 拼接成字符串.

5.1 toString(Object)

把对象 toBeConvertedValue 转换成字符串.

示例:

 ConvertUtil.toString(1)                  =   "1"
 ConvertUtil.toString(toBigDecimal(1.0))  =   "1.0"
 ConvertUtil.toString(toLong(8L))         =   "8"

注意:

  • 该方法不适合 list转换成字符串,比如:

      ConvertUtil.toString(toList("张飞", "关羽", "", "赵云")) = "张飞"

    ,请使用 toString(Collection, ToStringConfig)


该方法也不适合 array 转换成字符串,比如:

 Integer[] int1 = { 2, null, 1, null };
 LOGGER.debug(ConvertUtil.toString(int1));        = 2

**请使用 toString(Object [], ToStringConfig) **

对于 Array 转成 String: 参见 ArrayConverter#convertToString(Object) 在转换的过程中,如果发现object是数组,将使用 Array#get(Object, int)来获得数据, 如果发现不是数组,将会将object转成集合 ArrayConverter#convertToCollection(Class, Object)再转成迭代器 Collection.iterator()

在将object转成集合 ArrayConverter#convertToCollection(Class, Object)时候,有以下规则:

The string is expected to be a comma-separated list of values. 字符串可以被'{' and '}'分隔符包裹. 去除前后空白. Elements in the list may be delimited by single or double quotes. Within a quoted elements, the normal Java escape sequences are valid. **默认: **

字段 说明
int defaultSize 指定构建的默认数组的大小 or if less than zero indicates that a null default value should be used.
char delimiter = ',' 分隔符,转成的string中的元素分隔符
char[] allowedChars = new char[] {'.', '-'} 用于java.io.StreamTokenizer分隔字符串
boolean onlyFirstToString = true; 只转第一个值

5.2 toString(Object[], ToStringConfig)

将数组 arrays 通过 ToStringConfig 拼接成字符串.

支持包装类型以及原始类型,比如 Integer [] arrays 或者 int []arrays

示例:

 ConvertUtil.toString(toArray("a","b"),new ToStringConfig())       =   "a,b"
 
 ToStringConfig toStringConfig=new ToStringConfig(",");
 toStringConfig.setIsJoinNullOrEmpty(false);
 ConvertUtil.toString(toArray("a","b",null),new ToStringConfig())  =   "a,b"
 
 int[] ints = { 2, 1 };
 ConvertUtil.toString(toArray(ints),new ToStringConfig())          =   "2,1"

关于 default ToStringConfig: 如果参数 toStringConfig 是null,则使用默认的规则:

  1. 连接符使用ToStringConfig.DEFAULT_CONNECTOR
  2. 拼接null或者empty元素
  3. 如果元素是null,使用StringUtils.EMPTY替代拼接
  4. 最后一个元素后面不拼接拼接符

5.3 toString(Collection<?>, ToStringConfig)

将集合 collection 使用拼接配置 toStringConfig 拼接成字符串.

示例:

 List<String> list = new ArrayList<>();
 list.add("feilong");
 list.add("");
 list.add("xinge");
 
 ToStringConfig toStringConfig = new ToStringConfig(",");
 toStringConfig.setIsJoinNullOrEmpty(false);
 
 ConvertUtil.toString(list,toStringConfig);

**输出: **

 feilong,xinge

你还可以使用这个方法来将集合换行输出,比如:

 List<String> list = toList("飞龙", "小金", "四金", "金金金金");
 
 ToStringConfig toStringConfig = new ToStringConfig(SystemUtils.LINE_SEPARATOR);
 LOGGER.debug(ConvertUtil.toString(list, toStringConfig));

**输出: **

 飞龙
 小金
 四金
 金金金金

关于 default ToStringConfig: 如果参数 toStringConfig 是null,则使用默认的规则:

  1. 连接符使用ToStringConfig.DEFAULT_CONNECTOR
  2. 拼接null或者empty元素
  3. 如果元素是null,使用StringUtils.EMPTY替代拼接
  4. 最后一个元素后面不拼接拼接符

6.转成字符串数组

方法 Description
toStrings(Object) 将 toBeConvertedValue 转成String数组.

toBeConvertedValue 转成String数组.

说明:

  • 该方法很适合将 非字符串数组的数组 转换成 字符串数组,比如
 URL[] urls = {
                URLUtil.newURL("http://www.exiaoshuo.com/jinyiyexing0/"),
                URLUtil.newURL("http://www.exiaoshuo.com/jinyiyexing1/"),
                URLUtil.newURL("http://www.exiaoshuo.com/jinyiyexing2/"),
                null };
 
 LOGGER.debug(JsonUtil.format(ConvertUtil.toStrings(urls)));

返回:

 [
 "http://www.exiaoshuo.com/jinyiyexing0/",
 "http://www.exiaoshuo.com/jinyiyexing1/",
 "http://www.exiaoshuo.com/jinyiyexing2/",
 null
 ]

还有诸如 Integer[] 转成 String[]

 ConvertUtil.toStrings(new Integer[] { 1, 2, 5 })     =   [ "1", "2", "5" ]

也可以将字符串 解析成数组 in the Java language into a List individual Strings for each element, 根据以下规则:

  1. The string is expected to be a comma-separated list of values.
  2. 自动去除开头的 '{' 和 结束的'}'.
  3. 每个元素前后的空格将会去除.
  4. Elements in the list may be delimited by single or double quotes. Within a quoted elements, the normal Java escape sequences are valid.

**示例: **

 ConvertUtil.toStrings("{5,4, 8,2;8 9_5@3`a}"); =  ["5","4","8","2","8","9","5","3","a"]

7.其他转换

方法 Description
toEnumeration(Collection) 将集合 collection 转成Enumeration.
toIterator(Object) 将 toBeConvertedValue转成Iterator类型.
toLocale(Object) 将对象转成 Locale.
toProperties(Map<String, String>) 将map转成 Properties.
convert(Object, Class) 将 toBeConvertedValue 转成指定 targetType 类型的对象.

7.1 toEnumeration(Collection)

将集合 collection 转成Enumeration.

说明:

  • 一般情况,你可能不需要这个方法,不过在一些API的时候,需要Enumeration参数,此时调用这个方法来进行转换会比较方便

示例:

 ConvertUtil.toEnumeration(null) = Collections.emptyEnumeration()

7.2 toIterator(Object)

toBeConvertedValue 转成Iterator类型.

示例:

 // null
 toIterator(null) = null
 
 //PrimitiveArray
 int[] i2 = { 1, 2 };
 Iterator<Integer> iterator = toIterator(i2);
 
 //逗号分隔的字符串
 Iterator<String> iterator = toIterator("1,2");
 
 //collection
 List<String> list = new ArrayList<>();
 list.add("aaaa");
 list.add("nnnnn");
 
 Iterator<String> iterator = toIterator(list);
 
 //Enumeration
 Enumeration<Object> enumeration = new StringTokenizer("this is a test");
 Iterator<String> iterator = toIterator(enumeration);

支持以下类型:

  • 逗号分隔的字符串,先使用ConvertUtil.toStrings(Object) 转成数组
  • 数组(包括 包装类型数组 以及 原始类型数组)
  • 如果是java.util.Map,将 java.util.Map.values() 转成java.util.Iterator
  • java.util.Collection
  • java.util.Iterator
  • java.util.Enumeration
  • java.util.Dictionary
  • org.w3c.dom.Node
  • org.w3c.dom.NodeList

7.3 toLocale(Object)

将对象转成 Locale.

示例:

 ConvertUtil.toLocale(null)       = null
 ConvertUtil.toLocale("zh_CN")    = Locale.CHINA

7.4 toProperties(Map<String, String>)

将map转成 Properties.

说明:

  • 由于 Properties 只能保存非空的key和value,因此如果map 有key或者value是null,将会抛出 NullPointerException

示例:

 Map<String, String> map = toMap("name", "feilong");
 Properties properties = ConvertUtil.toProperties(map);
 
 LOGGER.debug(JsonUtil.format(properties));

返回:

 {"name": "feilong"}

7.5 convert(Object, Class)

toBeConvertedValue 转成指定 targetType 类型的对象.

示例:

 ConvertUtil.convert("1", Integer.class)      =1
 ConvertUtil.convert("", Integer.class)       =0
 ConvertUtil.convert("1", Long.class)         =1

此外,该方法特别适合数组类型的转换,比如 Type[] 转成 Class []: 原来的写法:

 Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
 int length = actualTypeArguments.length;
 Class<?>[] klasses = new Class<?>[length];
 for (int i = 0, j = length; i < j; ++i){
     klasses[i] = (Class<?>) actualTypeArguments[i];
 }
 
 return klasses;

现在可以重构成:

 Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
 return convert(actualTypeArguments, Class[].class);

注意:

  1. 如果targetType的转换器没有注册,那么传入的value原样返回, 比如ConvertUtil.convert("zh_CN", Locale.class) 由于找不到converter,那么返回"zh_CN".
  2. 如果转换不了,会使用默认值
  3. 如果传的 toBeConvertedValuetoBeConvertedValue.getClass().isArray() 或者 Collection
    1. 如果 targetType 不是数组 那么会取第一个元素进行转换, 参见AbstractConverter.convert(Class, Object),调用的 AbstractConverter.convertArray(Object) 方法

    2. 如果 targetType 是数组 参见 ArrayConverter#convertToType(Class, Object) 会基于targetType 构造一个数组对象,大小长度就是 toBeConvertedValue的大小或者长度, 然后迭代 toBeConvertedValue 依次进行转换

Clone this wiki locally