全能类型转换器 - ConvertUtil 在我们日常开发工作中, 类型转换是跑不掉的,下面特别封装十分常用的方法 主要由下面几个部分组成:  ## 1.转成数组 方法 | Description :---- | :--------- **toArray**(T...) | 将动态数组转成数组. **toArray**(Collection<T>, Class<T>) | 将集合 collection 转成数组. **toArray**(String[], Class<T>) | 将字符串数组 toBeConvertedValue 转成指定类型 targetType 的数组. ### 1.1 toArray(T...) 将动态数组转成数组. **示例:** ```JAVA 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 这将会导致下面的代码: ```JAVA 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; } ``` 调用的时候, ```JAVA 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 java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; ``` ### 1.2 toArray(Collection<T>, Class<T>) 将集合 collection 转成数组. **示例:** ```JAVA List<String> list = new ArrayList<>(); list.add("xinge"); list.add("feilong"); ``` 以前你需要写成: ```JAVA list.toArray(new String[list.size()]); ``` 现在你只需要写成: ```JAVA String[] array = ConvertUtil.toArray(list, String.class); LOGGER.info(JsonUtil.format(array)); ``` **返回:** ```JSON ["xinge","feilong"] ``` ### 1.3 toArray(String[], Class<T>) 将字符串数组 toBeConvertedValue 转成指定类型 targetType 的数组. **示例:** ```JAVA 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<T>) | 将 集合 collection 转成 list. **toList**(Enumeration<T>) | 将枚举 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: ```JAVA List<String> list = new ArrayList<>(); list.add("feilong1"); list.add("feilong2"); list.add("feilong2"); list.add("feilong3"); ``` 此时你可以使用: ```JAVA List<String> list = toList("feilong1", "feilong2", "feilong2", "feilong3"); ``` 代码会更简洁 **甚至于:** 有很多时候,参数需要一个对象list,构造的时候,你需要这样 ```JAVA List<UserAddress> userAddresseList = new ArrayList<>(); UserAddress userAddress = new UserAddress(); userAddress.setAddress("上海"); userAddresseList.add(userAddress); ``` 你可以重构成: ```JAVA UserAddress userAddress = new UserAddress(); userAddress.setAddress("上海"); List<UserAddress> userAddresseList = toList(userAddress); ``` ### 2.2 toList(Collection<T>) 将 集合 collection 转成 list. **说明:** - 此方法很适合快速的将set转成list这样的操作 **示例:** ```JAVA Set<String> set = new LinkedHashSet<>(); Collections.addAll(set, "a", "a", "b", "b"); LOGGER.debug("{}", toList(set)); ``` **返回:** ```JSON [a,b] ``` ### 2.3 toList(Enumeration<T>) 将枚举 enumeration 转成 List. **示例:** ```JAVA 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<I>, Class<J>) | 将诸如 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<E>) | 将 mapEntryCollection 转成map (LinkedHashMap). **toMapUseEntrys**(Entry<K, V>...) | 将 java.util.Map.Entry数组转成map (LinkedHashMap). ### 3.1 toMap(K, V) 将 key 和 value 直接转成map. **说明:** - 返回是的是 LinkedHashMap - 非常适合单key的场景,比如 ```JAVA Map<String, String> paramMap = new HashMap<>(); paramMap.put("name", "jinxin"); request.setParamMap(paramMap); ``` 上面的3行代码可以重写成 ```JAVA request.setParamMap(toMap("name", "jinxin")); ``` 一行代码就搞定了,很简洁,有木有~~ **示例:** ```JAVA LOGGER.debug(JsonUtil.format(ConvertUtil.toMap("张飞", "丈八蛇矛"))); ``` **返回:** ```JSON {"张飞": "丈八蛇矛"} ``` **重构:** 对于以下代码: ```JAVA private List<ShopCommand> loadShopCommandList(){ Map<String, Object> paraMap = new HashMap<>(); paraMap.put("orgTypeId", OrgType.ID_SHOP_TYPE); return shopCommandDao.findShopListByOrgaTypeId(paraMap); } ``` 可以重构成: ```JAVA 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的场景,比如 ```JAVA Map<String, String> paramMap = new HashMap<>(); paramMap.put("name", "jinxin"); paramMap.put("age", "18"); request.setParamMap(paramMap); ``` 上面的3行代码可以重写成 ```JAVA request.setParamMap(toMap("name", "jinxin", "age", "18")); ``` 一行代码就搞定了,很简洁,有木有~~ **重构:** 对于以下代码: ```JAVA Map<String, Long> map = new HashMap<>(); map.put("itemId", itemId); map.put("memberId", memberId); memberFavoritesDao.findMemberFavoritesByMemberIdAndItemId(map); ``` 可以重构成: ```JAVA Map<String, Long> map = ConvertUtil.toMap("itemId", itemId, "memberId", memberId); memberFavoritesDao.findMemberFavoritesByMemberIdAndItemId(map); ``` ### 3.3 toMap(Map<K, V>, Class<I>, Class<J>) 将诸如 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>` 类型 ```JAVA 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); } ``` 返回: ```JAVA key:[1],value:[2] ``` **场景2:** Map<String, String> 转 Map<Integer, Integer[]> ```JAVA 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); } ``` **返回:** ```JAVA key:[1],value:[[2, 2]] ``` **场景3:** Map<String[], String[]> 转 Map<Integer[], Long[]> ```JAVA 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> 类型 ```JAVA 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); } ``` **返回:** ```JAVA key:[1],value:[2] ``` **场景2:** Map<String, String> 转 Map<Integer, Integer[]> ```JAVA 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); } ``` **返回:** ```JAVA key:[1],value:[[2, 2]] ``` **场景3:** Map<String[], String[]> 转 Map<Integer[], Long[]> ```JAVA 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. **示例:** ```JAVA Properties properties = new Properties(); properties.setProperty("name", "feilong"); properties.setProperty("age", "18"); properties.setProperty("country", "china"); LOGGER.debug(JsonUtil.format(toMap(properties))); ``` **返回:** ```JSON { "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 示例:** ```JAVA Map<String, String> map = ConvertUtil.toMapUseEntrys( Pair.of("张飞", "丈八蛇矛"), Pair.of("关羽", "青龙偃月刀"), Pair.of("赵云", "龙胆枪"), Pair.of("刘备", "双股剑")); LOGGER.debug(JsonUtil.format(map)); ``` **返回:** ```JSON { "张飞": "丈八蛇矛", "关羽": "青龙偃月刀", "赵云": "龙胆枪", "刘备": "双股剑" } ``` **java.util.AbstractMap.SimpleEntry 示例:** ```JAVA Map<String, String> map = ConvertUtil.toMapUseEntrys( new SimpleEntry<>("张飞", "丈八蛇矛"), new SimpleEntry<>("关羽", "青龙偃月刀"), new SimpleEntry<>("赵云", "龙胆枪"), new SimpleEntry<>("刘备", "双股剑")); LOGGER.debug(JsonUtil.format(map)); ``` **返回:** ```JSON { "张飞": "丈八蛇矛", "关羽": "青龙偃月刀", "赵云": "龙胆枪", "刘备": "双股剑" } ``` **重构:** 以前初始化全局map的时候,你可能会这么写 ```JAVA // 除数和单位的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 } ``` 现在你可以重构成: ```JAVA // 除数和单位的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<E>) 将 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 示例: ```JAVA Map<String, String> map = toMap(toList(// Pair.of("张飞", "丈八蛇矛"), Pair.of("关羽", "青龙偃月刀"), Pair.of("赵云", "龙胆枪"), Pair.of("刘备", "双股剑"))); LOGGER.debug(JsonUtil.format(map)); ``` **返回:** ```JSON { "张飞": "丈八蛇矛", "关羽": "青龙偃月刀", "赵云": "龙胆枪", "刘备": "双股剑" } ``` java.util.AbstractMap.SimpleEntry 示例: ```JAVA Map<String, String> map = ConvertUtil.toMap( toList( new SimpleEntry<>("张飞", "丈八蛇矛"), new SimpleEntry<>("关羽", "青龙偃月刀"), new SimpleEntry<>("赵云", "龙胆枪"), new SimpleEntry<>("刘备", "双股剑"))); LOGGER.debug(JsonUtil.format(map)); ``` **返回:** ```JSON { "张飞": "丈八蛇矛", "关羽": "青龙偃月刀", "赵云": "龙胆枪", "刘备": "双股剑" } ``` ## 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类型. **示例:** ```JAVA 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: ```JAVA ConvertUtil.toInteger(new String[] { "1", "2", "3" }) = 1 ``` 如果传入的参数 `toBeConvertedValue` 是 集合,那么取第一个元素进行转换,参见 `AbstractConverter.convertArray(Object)` Line234: ```JAVA ConvertUtil.toInteger(toList("1", "2")) = 1 ``` 该方法非常适用 获取request请求的分页参数 **示例:** 原来的写法: ```JAVA 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 } ``` 现在可以更改成: ```JAVA 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)` 方法 ```JAVA 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. **示例:** ```JAVA 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: ```JAVA ConvertUtil.toInteger(new String[] { "1", "2", "3" }, 8) = 1 ``` 如果传入的参数 `toBeConvertedValue` 是 集合,那么取第一个元素进行转换,参见 `AbstractConverter.convertArray(Object)` Line234: ```JAVA ConvertUtil.toInteger(toList("1", "2"), 8) = 1 ``` 该方法非常适用 获取request请求的分页参数 **示例:** 原来的写法: ```JAVA 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 } ``` 现在可以更改成: ```JAVA 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依次逐个进行转换 **示例:** ```JAVA 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依次逐个进行转换 **示例:** ```JAVA 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 数组 示例: ```JAVA 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类型. **示例:** ```JAVA 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类型. **示例:** ```JAVA 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: ```JAVA ConvertUtil.toLong(new String[] { "1", "2", "3" }) = 1L ``` 如果传入的参数 `toBeConvertedValue` 是 集合,那么取第一个元素进行转换,参见 `AbstractConverter.convertArray(Object)` Line234: ```JAVA 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依次逐个进行转换 **示例:** ```JAVA 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依次逐个进行转换 示例: ```JAVA 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 数组 示例: ```JAVA 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[] {} ``` 特别适合以下形式的代码: ```JAVA 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; } ``` 可以重构成: ```JAVA protected long[] getOrderIdLongs(String orderIds){ return toLongs(orderIds); } ``` ### 4.7 toBigDecimal(Object) 将 toBeConvertedValue 转换成 java.math.BigDecimal. **示例:** ```JAVA 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: ```JAVA ConvertUtil.toBigDecimal(new String[] { "1", "2", "3" }) = BigDecimal.valueOf(1) ``` 如果传入的参数 toBeConvertedValue 是 集合,那么取第一个元素进行转换,参见 AbstractConverter.convertArray(Object) Line234: ```JAVA 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` 转换成字符串. **示例:** ```JAVA ConvertUtil.toString(1) = "1" ConvertUtil.toString(toBigDecimal(1.0)) = "1.0" ConvertUtil.toString(toLong(8L)) = "8" ``` **注意:** - 该方法不适合 list转换成字符串,比如: ```JAVA ConvertUtil.toString(toList("张飞", "关羽", "", "赵云")) = "张飞" ``` ,请使用 toString(Collection, ToStringConfig) -------------------------------------------------------------------------------- 该方法也不适合 array 转换成字符串,比如: ```JAVA 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` **示例:** ```JAVA 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 1. 拼接null或者empty元素 1. 如果元素是null,使用StringUtils.EMPTY替代拼接 1. 最后一个元素后面不拼接拼接符 ### 5.3 toString(Collection<?>, ToStringConfig) 将集合 collection 使用拼接配置 toStringConfig 拼接成字符串. **示例:** ```JAVA List<String> list = new ArrayList<>(); list.add("feilong"); list.add(""); list.add("xinge"); ToStringConfig toStringConfig = new ToStringConfig(","); toStringConfig.setIsJoinNullOrEmpty(false); ConvertUtil.toString(list,toStringConfig); ``` **输出: ** ```JAVA feilong,xinge ``` 你还可以使用这个方法来将集合换行输出,比如: ```JAVA List<String> list = toList("飞龙", "小金", "四金", "金金金金"); ToStringConfig toStringConfig = new ToStringConfig(SystemUtils.LINE_SEPARATOR); LOGGER.debug(ConvertUtil.toString(list, toStringConfig)); ``` **输出: ** ```JAVA 飞龙 小金 四金 金金金金 ``` **关于 default ToStringConfig:** 如果参数 toStringConfig 是null,则使用默认的规则: 1. 连接符使用ToStringConfig.DEFAULT_CONNECTOR 1. 拼接null或者empty元素 1. 如果元素是null,使用StringUtils.EMPTY替代拼接 1. 最后一个元素后面不拼接拼接符 ## 6.转成字符串数组 方法 | Description :---- | :--------- **toStrings**(Object) | 将 toBeConvertedValue 转成String数组. 将 `toBeConvertedValue` 转成String数组. **说明:** - 该方法很适合将 非字符串数组的数组 转换成 字符串数组,比如 ```JAVA 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))); ``` **返回:** ```JSON [ "http://www.exiaoshuo.com/jinyiyexing0/", "http://www.exiaoshuo.com/jinyiyexing1/", "http://www.exiaoshuo.com/jinyiyexing2/", null ] ``` 还有诸如 `Integer[] `转成 `String[] ` ```JAVA 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. 1. 自动去除开头的 '{' 和 结束的'}'. 1. 每个元素前后的空格将会去除. 1. Elements in the list may be delimited by single or double quotes. Within a quoted elements, the normal Java escape sequences are valid. **示例: ** ```JAVA ConvertUtil.toStrings("{5,4, 8,2;8 9_5@3`a}"); = ["5","4","8","2","8","9","5","3","a"] ``` ## 7.其他转换 方法 | Description :---- | :--------- **toEnumeration**(Collection<T>) | 将集合 collection 转成Enumeration. **toIterator**(Object) | 将 toBeConvertedValue转成Iterator类型. **toLocale**(Object) | 将对象转成 Locale. **toProperties**(Map<String, String>) |将map转成 Properties. **convert**(Object, Class<T>) | 将 toBeConvertedValue 转成指定 targetType 类型的对象. ### 7.1 toEnumeration(Collection<T>) 将集合 `collection` 转成Enumeration. **说明:** - 一般情况,你可能不需要这个方法,不过在一些API的时候,需要Enumeration参数,此时调用这个方法来进行转换会比较方便 **示例:** ```JAVA ConvertUtil.toEnumeration(null) = Collections.emptyEnumeration() ``` ### 7.2 toIterator(Object) 将 `toBeConvertedValue` 转成Iterator类型. **示例:** ```JAVA // 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`. **示例:** ```JAVA 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` **示例:** ```JAVA Map<String, String> map = toMap("name", "feilong"); Properties properties = ConvertUtil.toProperties(map); LOGGER.debug(JsonUtil.format(properties)); ``` **返回:** ```JSON {"name": "feilong"} ``` ### 7.5 convert(Object, Class<T>) 将 `toBeConvertedValue` 转成指定 `targetType` 类型的对象. **示例:** ```JAVA ConvertUtil.convert("1", Integer.class) =1 ConvertUtil.convert("", Integer.class) =0 ConvertUtil.convert("1", Long.class) =1 ``` 此外,该方法特别适合数组类型的转换,比如 Type[] 转成 Class []: 原来的写法: ```JAVA 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; ``` 现在可以重构成: ```JAVA Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); return convert(actualTypeArguments, Class[].class); ``` **注意:** 1. 如果targetType的转换器没有注册,那么传入的value原样返回, 比如ConvertUtil.convert("zh_CN", Locale.class) 由于找不到converter,那么返回"zh_CN". 2. 如果转换不了,会使用默认值 3. 如果传的 `toBeConvertedValue` 是 `toBeConvertedValue.getClass().isArray()` 或者 `Collection` 1. 如果 `targetType` 不是数组 那么会取第一个元素进行转换, 参见AbstractConverter.convert(Class, Object),调用的 AbstractConverter.convertArray(Object) 方法 2. 如果 `targetType` 是数组 参见 ArrayConverter#convertToType(Class, Object) 会基于targetType 构造一个数组对象,大小长度就是 toBeConvertedValue的大小或者长度, 然后迭代 toBeConvertedValue 依次进行转换