Java8: A new method Java8 in the Map interface

Java8 new interface methods in Map
We mention a demand: Given a List<String> statistics of all the location of each element appears.

For example, given List: ["a", "b", "b", "c", "c", "c", "d", "d", "d", "f", "f", "g"], it should return:

a : [0] b : [1, 2] c : [3, 4, 5] d : [6, 7, 8] f : [9, 10] g : [11]

Obviously, we are very suitable Mapto accomplish these things:

public static Map<String, List<Integer>> getElementPositions(List<String> list) {
    Map<String, List<Integer>> positionsMap = new HashMap<>();

    for (int i = 0; i < list.size(); i++) {
        String str = list.get(i);
        List<Integer> positions = positionsMap.get(str);

        if (positions == null) { // 如果 positionsMap 还不存在 str 这个键及其对应的 List<Integer>
            positions = new ArrayList<>(1);
            positionsMap.put(str, positions); // 将 str 及其对应的 positions 放入 positionsMap
        }

        positions.add(i); // 将索引加入 str 相关联的 List<Integer> 中
    }

    return positionsMap;
}

public static void main(String[] args) throws Exception {
    List<String> list = Arrays.asList("a", "b", "b", "c", "c", "c", "d", "d", "d", "f", "f", "g");

    System.out.println("使用 Java8 之前的 API:");
    Map<String, List<Integer>> elementPositions = getElementPositions(list);
    System.out.println(elementPositions);
}
复制代码

operation result:

Java8 operating results before the API

Java8, The Map<K, V>interface adds a new method putIfAbsent(K key, V value), function is: If the current Mapkey is not present keyor the keyassociated value null, then the execution put(key, value); otherwise, they will not perform put operations. This method is equivalent to the following code:

equivalent codes putIfAbsent

(Digression: putIfAbsentmethods and putmethods as returns before the method invocation parameters keyassociated value)

Using putIfAbsentmodified getElementPositionsmethods:

public static Map<String, List<Integer>> getElementPositions(List<String> list) {
    Map<String, List<Integer>> positionsMap = new HashMap<>();

    for (int i = 0; i < list.size(); i++) {
        String str = list.get(i);
        positionsMap.putIfAbsent(str, new ArrayList<>(1)); // 如果 positionsMap 不存在键 str 或者 str 关联的 List<Integer> 为 null,那么就会进行 put;否则不执行 put
        positionsMap.get(str).add(i);
    }

    return positionsMap;
}

public static void main(String[] args) throws Exception {
    List<String> list = Arrays.asList("a", "b", "b", "c", "c", "c", "d", "d", "d", "f", "f", "g");

    System.out.println("使用 putIfAbsent:");
    Map<String, List<Integer>> elementPositions = getElementPositions(list);
    System.out.println(elementPositions);
}
复制代码

operation result:

Use of operating results putIfAbsent

It can be seen using the putIfAbsentfollowing getElementPositionssimple point, that it could be more concise?

Check Mapthe interface method can be found in JDK1.8time, we add the following two methods:

compute method and the method computeIfAbsent

Check computemethod of APIdocuments, you can find computea method with the following code is equivalent to

 V oldValue = map.get(key);
 V newValue = remappingFunction.apply(key, oldValue);
 if (oldValue != null ) {
    if (newValue != null)
       map.put(key, newValue);
    else
       map.remove(key);
 } else { // 即 原来的 key 不存在 Map 中或该 key 关联的 value 为 null
    if (newValue != null)
       map.put(key, newValue);
    else
       return null;
 }
复制代码

computeThe original method and putthe difference method is:

put(K key, V value)Method, if keythe Mapdoes not exist, then added directly; if it already exists, then the use of the new valuereplacing the old value;

The compute(K key, BiFunction remappingFunction)method can be calculated by a new BiFunction value, BiFunctionthe old parameters keyand valuereturn to calculate a new value- and putdifferent methods, computethe method returns would be the latest and keyassociated value, instead of the old value. It is possible to use computea method rewritten getElementPositionsas follows:

public static Map<String, List<Integer>> getElementPositions(List<String> list) {
    Map<String, List<Integer>> positionsMap = new HashMap<>();

    for (int i = 0; i < list.size(); i++) {
        positionsMap.compute(list.get(i), (k, v) -> v == null ? new ArrayList<>(1) : v).add(i);
    }

    return positionsMap;
}

public static void main(String[] args) throws Exception {
    List<String> list = Arrays.asList("a", "b", "b", "c", "c", "c", "d", "d", "d", "f", "f", "g");

    System.out.println("使用 compute:");
    Map<String, List<Integer>> elementPositions = getElementPositions(list);
    System.out.println(elementPositions);
}
复制代码

(k, v) -> v == null ? new ArrayList<>(1) : vThat is, if the current value null, then the BiFunctionreturn value new ArrayList<>(1); if not null, then the return value is itself. And because the computemethod returns a new value- and at this time is the list.get(i)(key) associated with ArrayList- so we can call it a direct addapproach.

operation result:

Use of compute operating results

Great - but also more concise yet? Let us look at computeIfAbsentmethods: computeIfAbsentand computerelationship, similar to putIfAbsentand putrelationships: computeIfAbsentin keyabsence Mapor with keyassociated valueis nullonly when the function is performed by computing a new valueoperation, and otherwise does; computeIfAbsentthe return value is the keylatest associated a value. Its default implementation is as follows:

The default implementation computeIfAbsent

And computedifferent, computeIfAbsentacceptable operation is a function Functionand not BiFunction- this is well understood, computeIfAbsentonly key is not Map, or with the keyassociated valueto nullonly perform the function operation, then clearly this time and keyrelated valueto null, so computeIfAbsentonly accept Functioncan be used as parameters - which Functioncan be used keyas a new parameter calculation value. Use computeIfAbsentrewrite getElementPositions:

public static Map<String, List<Integer>> getElementPositions(List<String> list) {
    Map<String, List<Integer>> positionsMap = new HashMap<>();

    for (int i = 0; i < list.size(); i++) {
        positionsMap.computeIfAbsent(list.get(i), k -> new ArrayList<>(1)).add(i);
    }

    return positionsMap;
}

public static void main(String[] args) throws Exception {
    List<String> list = Arrays.asList("a", "b", "b", "c", "c", "c", "d", "d", "d", "f", "f", "g");

    System.out.println("使用 computeIfAbsent:");
    Map<String, List<Integer>> elementPositions = getElementPositions(list);
    System.out.println(elementPositions);
}
复制代码

operation result:

Use of operating results computeIfAbsent

In fact, as used herein, putIfAbsentwas present when the issue positionsMap.putIfAbsent(str, new ArrayList<>(1)); this code when each call will have a temporary ArrayList- when traversed List<String>when large, this may bring some negative effects; contrast computeand computeIfAbsentbenefits that they accept the parameters for the function, it will only be calculated when necessary to use a new function value. In the case of this paper, similar needs, you applicability and simplicity, it computeIfAbsentis superior compute. In JDK1.8the API documentation, also said in the need to generate a similar Map<K, Collection<V>>time of construction, computeIfAbsentit is suitable for this situation:

computeIfAbsent the JavaDoc documentation

That computemethod is suitable for what happens then? Seen from the preceding description, computethe method is more suitable for updating keythe associated valuetime, the new value of the old value depends on the situation - such as a count List<String>the number of times each element appears:

public static Map<String, Integer> getElementCounts(List<String> list) {
    Map<String, Integer> countsMap = new HashMap<>();

    list.forEach(str -> countsMap.compute(str, (k, v) -> v == null ? 1 : v + 1)); // 此时:新值 = 旧值 + 1

    return countsMap;
}

public static void main(String[] args) throws Exception {
    List<String> list = Arrays.asList("a", "b", "b", "c", "c", "c", "d", "d", "d", "f", "f", "g");
    System.out.println("使用 compute 计算元素出现的次数:");
    Map<String, Integer> counts = getElementCounts(list);
    System.out.println(counts);
}
复制代码

operation result:

Calculated using the number of compute elements appear

Java8Is also Mapadded some other new methods to facilitate encoding, interested readers continue to explore.

Original Address: segmentfault.com/a/119000000...

recommend

Manufacturers written content collection (with detailed analytical) continuously updated in ....

ProcessOn aggregation platform is an online mapping tool -

The end of the sentence

Welcome attention to personal micro-channel public number: Coder programming welcome attention Coder programming public numbers, the main share data structures and algorithms, Java-related knowledge, the framework of knowledge and principle, Spring family bucket, micro-services project combat, DevOps practices of the road, one day Internet giant pen articles or interview questions and PMP project management knowledge. More exciting content is on the way - built a qq group: 315 211 365, we welcome into the group exchange study together. Thank you! Can also be introduced to the side of a friend in need.

Articles included to Github: github.com/CoderMerlin... Gitee: gitee.com/573059382/c... welcome attention and star ~

Micro-channel public number

Guess you like

Origin juejin.im/post/5daef2dee51d4524b601bf52