Java数据转换及属性获取
一、数据转换
(1)数据转换工具类
/** * 数据转换工具类 * @author songwp */ public class DataUtils{ /** * 定义分割常量 * #用于list中每个元素间的分割 * |用于map中每一个kv对间的分割 * =用于map中key与value间的分割 */ private static final String SEP1 = ","; private static final String SEP2 = "|"; private static final String SEP3 = "="; private static final String SEP4 = ";"; /** * List转换String * * @param list 需要转换的List * @return String 转换后的字符串 */ public static String ListToString(List<?> list) { StringBuffer sb = new StringBuffer(); if (list != null && list.size() > 0) { for (int i = 0; i < list.size(); i++) { if (list.get(i) == null || list.get(i) == "") { continue; } // 如果值是list类型则调用自己 if (list.get(i) instanceof List) { sb.append(ListToString((List<?>) list.get(i))); sb.append(SEP1); } else if (list.get(i) instanceof Map) { sb.append(MapToString((Map<?, ?>) list.get(i))); sb.append(SEP1); } else { sb.append(list.get(i)); sb.append(SEP1); } } } return sb.toString(); } /** * Map转换String * * @param map 需要转换的Map * @return String 转换后的字符串 */ public static String MapToString(Map<?, ?> map) { StringBuffer sb = new StringBuffer(); // 遍历map for (Object obj : map.keySet()) { if (obj == null) { continue; } Object key = obj; Object value = map.get(key); if (value instanceof List<?>) { sb.append(key.toString() + SEP1 + ListToString((List<?>) value)); sb.append(SEP2); } else if (value instanceof Map<?, ?>) { sb.append(key.toString() + SEP1 + MapToString((Map<?, ?>) value)); sb.append(SEP2); } else { if (value == null) { sb.append(key.toString() + SEP3 + "0"); sb.append(SEP2); } else { sb.append(key.toString() + SEP3 + value.toString()); sb.append(SEP2); } } } return sb.toString(); } /** * String转换Map * * @param mapText 需要转换的字符串 * @return Map<?,?> */ public static Map<String, Object> StringToMap(String mapText) { if (mapText == null || mapText.equals("")) { return null; } mapText = mapText.substring(1); Map<String, Object> map = new HashMap<String, Object>(); String[] text = mapText.split("\\" + SEP2); // 转换为数组 for (String str : text) { String[] keyText = str.split(SEP3); // 转换key与value的数组 if (keyText.length < 1) { continue; } String key = keyText[0]; // key String value = keyText[1]; // value if (value.charAt(0) == 'M') { Map<?, ?> map1 = StringToMap(value); map.put(key, map1); } else if (value.charAt(0) == 'L') { List<?> list = StringToList(value); map.put(key, list); } else { map.put(key, value); } } return map; } /** * String转换List * * @param listText 需要转换的文本 * @return List<?> */ public static List<Object> StringToList(String listText) { if (listText == null || listText.equals("")) { return null; } listText = listText.substring(0); List<Object> list = new ArrayList<Object>(); String[] text = listText.split("\\" + SEP1); String listStr = ""; boolean flag = false; for (String str : text) { if (!str.equals("")) { if (str.charAt(0) == 'M') { Map<?, ?> map = StringToMap(str); list.add(map); } else if (str.charAt(0) == 'L' || flag) { flag = true; listStr += str + SEP1; } else { list.add(str); } } if (str.equals("")) { flag = false; List<?> lists = StringToList(listStr); list.add(lists); } } return list; } public static void main(String[] args) { // 1. List转换String List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); String listToString = ListToString(list); System.out.println("List转换String:" + listToString); Map<String, Object> map = new HashMap<String, Object>(); map.put("name", "刘德华"); map.put("age", 56); map.put("address", "北京市海淀区"); // 2. Map转换String String mapToString = MapToString(map); System.out.println("Map转换String: " + mapToString); // 3. String转换Map Map<String, Object> map1 = StringToMap(mapToString); System.out.println("String转换Map: " + map1); // 4. String转换List List<Object> list1 = StringToList(listToString); System.out.println("String转换List: " + list1); } }
(2)控制台输出如下:
二、数据获取
(1)数据获取的具体代码实例:
public static void main(String[] args) { // 1.数据准备 List<Map<String,Object>> list = new ArrayList<>(); Map<String,Object> map = new HashMap<>(); map.put("name", "尼古拉斯赵六"); map.put("age", 25); map.put("address", "广东广州"); Map<String,Object> map1 = new HashMap<>(); map1.put("name", "令狐冲"); map1.put("age", 26); map1.put("address", "陕西西安"); Map<String,Object> map2 = new HashMap<>(); map2.put("name", "李思思"); map2.put("age", 24); map2.put("address", "中国上海"); list.add(map); list.add(map1); list.add(map2); System.out.println("原始数据:"+list); // 2.根据name转成Map Map<Object, Map<String, Object>> resultMap = list.stream().collect(Collectors.toMap(m -> m.get("name"), m -> m)); System.out.println("根据name转成Map的结果:"+resultMap); // 3.根据name转成List List<Object> names = list.stream().map(m -> m.get("name")).collect(Collectors.toList()); System.out.println("根据name转成List的结果;"+names); List<User> jsonArray = (List<User>)JSON.parseArray(JSON.toJSONString(list), User.class); System.out.println(jsonArray); // 4.将List<Map<String, Object>>转换为List<Object> List<Object> listObject = list.stream() .flatMap(m -> m.values().stream()) .collect(Collectors.toList()); System.out.println(listObject); }
(2)控制台输出如下:
三、Map数据操作
Map是我们日常编程中十分常用的数据接口,的在JDK8中,Map引入了几个新方法,可以简化我们对Map中数据的操作。
getOrDefault
这个方法名很直观,见名知意:尝试获取key对应的值,如果未获取到,就返回默认值。
看一个使用的例子,新写法会比老写法更加简洁:
private static void testGetOrDefault() { Map<String, String> map = new HashMap<>(4); map.put("123", "123"); String key = "key"; String defaultValue = "defaultValue"; // 老写法 String oldValue = defaultValue; if (map.containsKey(key)) { oldValue = map.get(key); } System.out.println("oldValue = " + oldValue); // 新写法 String newValue = map.getOrDefault(key, defaultValue); System.out.println("newValue = " + newValue); }
foreach
看方法名也可以知道,这个方法是遍历map的数据使用的。
如果没有foreach,我们遍历map的时候一般是使用增强for循环,有了这个方法后,可以更加方便使用entry中的key和val:
private static void testForeach() { Map<String, String> map = new HashMap<>(4); map.put("123", "123"); // 老写法 for (Map.Entry<String, String> entry : map.entrySet()) { System.out.printf("老写法 key = %s, value = %s%n", entry.getKey(), entry.getValue()); } // 新写法 map.forEach((key, value) -> System.out.printf("新写法 key = %s, value = %s%n", key, value)); }
merge
从名字可以想到,是合并entry使用的,但是具体是怎么合并呢?
看一下日常最常用的Map实现类HashMap对merge方法的实现
@Override public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { if (value == null || remappingFunction == null) throw new NullPointerException(); int hash = hash(key); Node<K,V>[] tab; Node<K,V> first; int n, i; int binCount = 0; TreeNode<K,V> t = null; Node<K,V> old = null; if (size > threshold || (tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode) old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key); else { Node<K,V> e = first; K k; do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { old = e; break; } ++binCount; } while ((e = e.next) != null); } } if (old != null) { V v; if (old.value != null) { int mc = modCount; v = remappingFunction.apply(old.value, value); if (mc != modCount) { throw new ConcurrentModificationException(); } } else { v = value; } if (v != null) { old.value = v; afterNodeAccess(old); } else removeNode(hash, key, null, false, true); return v; } else { if (t != null) t.putTreeVal(this, tab, hash, key, value); else { tab[i] = newNode(hash, key, value, first); if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash); } ++modCount; ++size; afterNodeInsertion(true); return value; } }
代码比较长,但是实现的效果比较容易描述:这个方法接收3个参数:key、value、function。
- 如果key存在,将value按照function做1次计算后,更新到Map中
- 如果key不存在,将key-value放入Map中
这个方法在某些场景中挺好用的,代码简洁易懂,例如:我们有1个List,要统计List中每个元素出现的次数。我们要实现的逻辑是,遍历List中的每个元素,如果这个元素在Map中存在,Map中的值+1;如果不存在,则放入Map中,次数(值)为1。
private static void testMerge() { Map<String, Integer> cntMap = new HashMap<>(8); List<String> list = Arrays.asList("apple", "orange", "banana", "orange"); // 老写法 for (String item : list) { if (cntMap.containsKey(item)) { cntMap.put(item, cntMap.get(item) + 1); } else { cntMap.put(item, 1); } } // 新写法 for (String item : list) { cntMap.merge(item, 1, Integer::sum); } }
可以看到我们使用merge方法的话,只用1行就简洁实现了这个逻辑。
putIfAbsent
也是一个见名知意的方法:不存在key或者值为null时,才将键值对放入Map。跟put方法相比,这个方法不会直接覆盖已有的值,在不允许覆盖旧值的场景使用起来会比较简洁。
private static void testPutIfAbsent() { Map<String, Integer> scoreMap = new HashMap<>(4); scoreMap.put("Jim", 88); scoreMap.put("Lily", 90); // 老写法 if (!scoreMap.containsKey("Lily")) { scoreMap.put("Lily", 98); } // 新写法 scoreMap.putIfAbsent("Lily", 98); }
computer
computer方法需要传入2个参数:key、function。主要有3步操作
- 获取到key对应的oldValue,可能为null
- 经过function计算获取newValue
- put(key, newValue)
还是以刚刚统计单次次数需求为例,看一下computer的写法:
private static void testComputer() { Map<String, Integer> cntMap = new HashMap<>(8); List<String> list = Arrays.asList("apple", "orange", "banana", "orange"); // 老写法 for (String item : list) { if (cntMap.containsKey(item)) { cntMap.put(item, cntMap.get(item) + 1); } else { cntMap.put(item, 1); } } // 新写法 for (String item : list) { cntMap.compute(item, (k, v) -> { if (v == null) { v = 1; } else { v += 1; } return v; }); } }
computeIfAbsent
看名字就知道是compute方法衍生出来的方法,这个方法只在key不存在的时候,执行computer计算,如果说key对应的value存在,就直接返回这个value。
例如,我们需要计算斐波那锲数列的时候,可以使用这个方法来简化代码:
private static void testComputerIfAbsent() { Map<Integer, Integer> fabMap = new ConcurrentHashMap<>(16); fabMap.put(0, 1); fabMap.put(1, 1); System.out.println(fab(5, fabMap)); } private static Integer fab(Integer index, Map<Integer, Integer> fabMap) { return fabMap.computeIfAbsent(index, i -> fab(i - 2, fabMap) + fab(i - 1, fabMap)); }
computeIfPresent
这个是computeIfAbsent的姊妹方法,区别在于,这个方法是只有key存在的时候,才去执行computer计算和值的更新。
replace
这个方法的效果是:
- 如果key存在,则更新值
- 如果key不存在,什么也不做