Skillfully use one line of HashMap code to count the number of words

brief introduction

JDK has been updated iteratively, and many familiar classes have quietly added some new method features. For example, our most commonly used HashMap.

Today, let's talk about two new methods compute and merge added by HashMap in jdk8, so as to realize the function of word statistics in one line of code. Let's have a look.

Love before jdk8

Jdk8 introduces many very useful new features for us, such as stream and lambda expressions, which can make our program more concise.

What if we need to count the number of words in an array?

This is not about algorithms, so you can directly use HashMap:

public void countBefore8(){
        Map<String,Integer> wordCount=  new HashMap<>();
        String[] wordArray= new String[]{"we","are","the","world","we"};
        for(String word: wordArray){
            //如果存在则加1,否则将值设置为1
            if(wordCount.containsKey(word)) {
                wordCount.put(word,wordCount.get(word) + 1);
            }else{
                wordCount.put(word,1);
            }
        }
    }

Basically, the process is like the above. We traverse the array, and then judge whether the word exists in the HashMap. If it exists, + 1.

The logic is simple, but it looks bloated.

Don't be afraid, we have jdk8.

Use compute in jdk8

Let's first look at the definition of compute in jdk8:

default V compute(K key,BiFunction<? super K,? super V,? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        V oldValue = get(key);

        V newValue = remappingFunction.apply(key,oldValue);
        if (newValue == null) {
            // delete mapping
            if (oldValue != null || containsKey(key)) {
                // something to remove
                remove(key);
                return null;
            } else {
                // nothing to do. Leave things as they were.
                return null;
            }
        } else {
            // add or replace old mapping
            put(key,newValue);
            return newValue;
        }
    }

You can see that compute has the second parameter bifunction. Bifunction is a function. Enter two parameters and return one parameter.

The two parameters of bifunction are key and oldvalue corresponding to key.

Considering our word statistics, we can directly add oldvalue + 1. Therefore, using compute, you can rewrite the method to:

public void countAfter8WithCompute(){
        Map<String,"we"};
        Arrays.asList(wordArray).forEach(word ->{
            wordCount.putIfAbsent(word,0);
            wordCount.compute(word,(w,count)->count+1);
        });
    }

Of course, we can put putifabsent into compute:

public void countAfter8WithCompute2(){
        Map<String,"we"};
        Arrays.asList(wordArray).forEach(word -> wordCount.compute(word,count)->count == null ? 1 : count + 1));
    }

One line of code is complete.

Merge used in jdk8

Take another look at the merge method:

default V merge(K key,V value,BiFunction<? super V,? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        Objects.requireNonNull(value);
        V oldValue = get(key);
        V newValue = (oldValue == null) ? value :
                   remappingFunction.apply(oldValue,value);
        if (newValue == null) {
            remove(key);
        } else {
            put(key,newValue);
        }
        return newValue;
    }

The merge method requires three parameters. The first parameter is a key, the second parameter is a value with an empty oldvalue corresponding to the key, that is, a null default value, and the third parameter is a bifunction parameter.

The difference is that the first parameter of bifunction is oldvalue and the second parameter is value.

The logic of generating newvalue is: if oldvalue does not exist, use value. If oldvalue exists, call bifunction to merge oldvalue and value.

We can write the corresponding code as follows:

 public void countAfter8WithMerge(){
        Map<String,"we"};
        Arrays.asList(wordArray).forEach(word->wordCount.merge(word,1,(oldCount,one) -> oldCount + one));
    }

The following functions can be replaced by integer:: sum:

 public void countAfter8WithMerge(){
        Map<String,Integer::sum));
    }

Examples of this article https://github.com/ddean2009/learn-java-base-9-to-20/tree/master/java-base

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>