zoukankan      html  css  js  c++  java
  • lambda表达式操作map

    为引入Lambda表达式,Java8新增了java.util.funcion包,里面包含常用的函数接口,这是Lambda表达式的基础,Java集合框架也新增部分接口,以便与Lambda表达式对接。

    首先回顾一下Java集合框架的接口继承结构:

    上图中绿色标注的接口类,表示在Java8中加入了新的接口方法,当然由于继承关系,他们相应的子类也都会继承这些新方法。下表详细列举了这些方法:

    接口名 Java8新加入的方法
    Collection removeIf()、spliterator()、 stream()、 parallelStream() 、forEach()
    List replaceAll() 、sort()
    Map getOrDefault()、 forEach()、 replaceAll()、 putIfAbsent() 、remove()、 replace() 、computeIfAbsent() 、computeIfPresent()、 compute()、 merge()

    这些新加入的方法大部分要用到java.util.function包下的接口,这意味着这些方法大部分都跟Lambda表达式相关。


    相比CollectionMap中加入了更多的方法,下面一起了解一下。

    (1)forEach() 以hashMap为例说明forEach()方法

    该方法签名为void forEach(BiConsumer<? super K,? super V> action)作用是对Map中的每个映射执行action指定的操作,其中BiConsumer是一个函数接口,里面有一个待实现方法void accept(T t, U u)BinConsumer接口名字和accept()方法名字都不重要,请不要记忆他们。

    需求:假设有一个数字到对应英文单词的Map,请输出Map中的所有映射关系。

    Map<Integer, String> map = new HashMap<>(16);
    map.put(1, "one");
    map.put(2, "two");
    map.put(3, "three");
    map.put(4, "four");
    map.put(5, "five");
    
    // Java7以及之前写法
    for (Map.Entry<Integer, String> entry : map.entrySet()) {
        System.out.println(entry.getKey() + "=" + entry.getValue());
    }
    
    // 使用Map.forEach()方法,并使用匿名内部类实现BiConsumer接口
    map.forEach(new BiConsumer<Integer, String>() {
        @Override
        public void accept(Integer integer, String s) {
            System.out.println("key=" + integer + " value=" + s);
        }
    });
    
    // 使用lambda表达式
    map.forEach((k,v)-> System.out.println("key="+k+" value="+v));
    

    (2)getOrDefault() 以hashMap为例说明getOrDefault()方法

    该方法跟Lambda表达式没关系,但是很有用。方法签名为V getOrDefault(Object key, V defaultValue)作用是按照给定的key查询Map中对应的value,如果没有找到则返回设置的默认值defaultValue使用该方法程序员可以省去查询指定键值是否存在的麻烦。

    需求;假设有一个数字到对应英文单词的Map,输出4对应的英文单词,如果不存在则输出NoValue。

    Map<Integer, String> map = new HashMap<>(16);
    map.put(1, "one");
    map.put(2, "two");
    map.put(3, "three");
    map.put(4, "four");
    map.put(5, "five");
    
    // Java7以及之前做法
    if (map.containsKey(6)) {
        System.out.println(map.get(4));
    } else {
        System.out.println("NoValue");
    }
    
    // Java8使用Map.getOrDefault(),如果不存在直接返回NoValue
    System.out.println(map.getOrDefault(6, "NoValue"));
    

    (3)putIfAbsent() 以hashMap为例说明putIfAbsent()方法

    该方法跟Lambda表达式没关系,但是很有用。方法签名为V putIfAbsent(K key, V value)作用是只有在不存在key值的映射或映射值为null时,才将value指定的值放入到Map中,否则不对Map做更改。该方法将条件判断和赋值合二为一,使用起来更加方便。

    Map<Integer, String> map = new HashMap<>(16);
    map.put(1, "one");
    map.put(2, "two");
    map.put(3, "three");
    map.put(4, "four");
    map.put(5, "five");
    map.put(6,null);
    
    map.putIfAbsent(6, "null-six");
    map.forEach((k, v) -> {
        System.out.println("k=" + k + " v=" + v);
    });
    

    (4)remove(Object key, Object value) 以hashMap为例说明remove()方法

    我们都知道Map中有一个remove(Object key)方法,来根据指定key值删除Map中的映射关系;Java8新增了remove(Object key, Object value)方法,只有在当前Mapkey正好映射到value时才删除该映射,否则什么也不做。

    Map<Integer, String> map = new HashMap<>(16);
    map.put(1, "one");
    map.put(2, "two");
    map.put(3, "three");
    map.put(4, "four");
    map.put(5, "five");
    
    map.remove(5,"five");
    map.forEach((k,v)-> System.out.println("key="+k+" value="+v));
    

    (5)replace() 以hashMap为例说明replace()方法

    在Java7及以前,要想替换Map中的映射关系可通过put(K key, V value)方法实现,该方法总是会用新值替换原来的值。为了更精确的控制替换行为,Java8在Map中加入了两个replace()方法,分别如下:

    • replace(K key, V value),只有在当前Mapkey的映射存在时才用value去替换原来的值,否则什么也不做。
    • replace(K key, V oldValue, V newValue)只有在当前Mapkey的映射存在且等于oldValue时才用newValue去替换原来的值,否则什么也不做
    Map<Integer, String> map = new HashMap<>(16);
    map.put(1, "one");
    map.put(2, "two");
    map.put(3, "three");
    map.put(4, "four");
    map.put(5, "five");
    
    // 因为map中key不可重复,因此会替换掉以前key对应的value
    map.put(5, "five1");
    // 如果存在对应的key,则替换掉对应key的值
    map.replace(5, "six");
    
    // map中存在key-value的映射才使用newValue替换掉oldValue
    map.replace(5, "five", "newfive");
    map.forEach((k, v) -> System.out.println("key=" + k + " value=" + v));
    

    (6)replaceAll() 以hashMap为例说明replaceAll()方法

    该方法签名为replaceAll(BiFunction<? super K,? super V,? extends V> function)作用是对Map中的每个映射执行function指定的操作,并用function的执行结果替换原来的value其中BiFunction是一个函数接口,里面有一个待实现方法R apply(T t, U u)

    需求:假设有一个数字到对应英文单词的Map,请将原来映射关系中的单词都转换成大写。

    Map<Integer, String> map = new HashMap<>(16);
    map.put(1, "one");
    map.put(2, "two");
    map.put(3, "three");
    map.put(4, "four");
    map.put(5, "five");
    
    // Java7以及之前替换Map中所有映射关系
    for (Map.Entry<Integer, String> entry : map.entrySet()) {
        entry.setValue(entry.getValue().toUpperCase());
    }
    // 遍历输出映射key-value
    map.forEach((k, v) -> System.out.println("key=" + k + " value=" + v));
    
    // 调用replaceAll()方法,并使用匿名内部类实现BiFunction接口
    map.replaceAll(new BiFunction<Integer, String, String>() {
        @Override
        public String apply(Integer integer, String s) {
            return s.toUpperCase();
        }
    });
    // 遍历输出映射key-value
    map.forEach((k, v) -> System.out.println("key=" + k + " value=" + v));
    
    // 使用replaceAll()并结合Lambda表达式实现
    map.replaceAll((k, v) -> v.toUpperCase());
    // 遍历输出映射key-value
    map.forEach((k, v) -> System.out.println("key=" + k + " value=" + v));
    

    (7)merge() 以hashMap为例说明merge()方法

    该方法签名为merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)作用是:如果Mapkey对应的映射不存在或者为null,则将value(不能是null)关联到key上,否则执行remappingFunction;如果执行结果非null则用该结果跟key关联,否则在Map中删除key的映射。

    也就是说如果key存在就把newvalue拼接在这个key对应的value上,如果不存在就把这个newValue与key进行映射,put到map中。如下代码所示:

    Map<Integer, String> map = new HashMap<>(16);
    map.put(1, "one");
    map.put(2, "two");
    map.put(3, "three");
    map.put(4, "four");
    map.put(5, "five");
    map.put(6, "six");
    
    // 使用匿名内部类实现BiFunction接口
    map.merge(6, "+", new BiFunction<String, String, String>() {
        @Override
        public String apply(String s, String s2) {
            return s + s2;
        }
    });
    // 遍历输出key-value
    map.forEach((k, v) -> System.out.println("key=" + k + " value=" + v));
    
    // 使用lambda表达式实现
    map.merge(6, "+", (s, s2) -> s + s2);
    // 遍历输出key-value
    map.forEach((k, v) -> System.out.println("key=" + k + " value=" + v));
    

    (8)compute() 以hashMap为例说明compute()方法

    该方法签名为compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction),作用是把remappingFunction的计算结果关联到key上,如果计算结果为null,则在Map中删除key的映射。 也就是说,如果计算的结果为null则把这个key-value映射给删掉,如果计算结果不为空,则把这个计算结果覆盖掉以前的value。

    Map<Integer, String> map = new HashMap<>(16);
    map.put(1, "one");
    map.put(2, "two");
    map.put(3, "three");
    map.put(4, "four");
    map.put(5, "five");
    map.put(6, "six");
    
    // 使用匿名内部类实现BiFunction接口写法
    map.compute(5, new BiFunction<Integer, String, String>() {
      @Override
      public String apply(Integer integer, String s) {
          return s == null ? "null" : s + " is not null";
      }
    });
    
    // lambda表达式写法
    map.compute(5, (integer, s) -> s == null ? "null" : s + "is not null");
    
    // 遍历输出key-value映射
    map.forEach((k, v) -> System.out.println("key=" + k + " value=" + v));
    

    (9)computeIfAbsent() 以hashMap为例说明computeIfAbsent()方法

    该方法签名为V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)作用是:只有在当前Map中不存在key值的映射或映射值为null时,才调用mappingFunction,并在mappingFunction执行结果非null时,将结果跟key关联。

    Function是一个函数接口,里面有一个待实现方法R apply(T t)computeIfAbsent()常用来对Map的某个key值建立初始化映射。

    比如我们要实现一个多值映射,Map的定义可能是Map<K,Set<V>>,要向Map中放入新值,可通过如下代码实现:

    // 实现一个key对应多个值
    Map<Integer, Set<String>> map = new HashMap<>(16);
    // Java7及以前的实现方式
    if (map.containsKey(1)) {
        map.get(1).add("one");
    } else {
        Set<String> valueSet = new HashSet<>();
        valueSet.add("one");
        map.put(1, valueSet);
    }
    
    // Java8的实现方式 即它会判断一下这个key是否存在并且key对应的value是否为空,
    // 如果key存在且key对应的value不为null,则将这个value关联到对应的key上,即在原来的value中新增一个value
    // 如果key不存在,则新增一个key-value映射关系
    map.computeIfAbsent(1, v -> new HashSet<>()).add("oneone");
    
    // 遍历输出key-value映射
    map.forEach((k, v) -> System.out.println("key=" + k + " value=" + v));
    

    使用computeIfAbsent()将条件判断和添加操作合二为一,使代码更加简洁。


    (10)computeIfPresent() 以hashMap为例说明computeIfPresent()方法

    该方法签名为V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)作用跟computeIfAbsent()相反,即只有在当前Map中存在key值的映射且非null时,才调用remappingFunction,如果remappingFunction执行结果为null,则删除key的映射,否则使用该结果替换key原来的映射。

    这个函数的功能跟如下代码是等效的:

    Map<Integer, Set<String>> map = new HashMap<>(16);
    // Java7及以前的实现方式
    if (map.containsKey(1)) {
        map.get(1).add("one");
    } else {
        Set<String> valueSet = new HashSet<>();
        valueSet.add("one");
        map.put(1, valueSet);
    }
    
    // 匿名内部类实现BiFunction接口,如果key存在并且计算结果不为null时将计算的结果替换掉key对应的原来的值
    map.computeIfPresent(8, new BiFunction<Integer, Set<String>, Set<String>>() {
        @Override
        public Set<String> apply(Integer integer, Set<String> strings) {
            Set<String> set = new HashSet<>();
            set.add("888");
            return set;
        }
    });
    
    // lambda表达式实现
    map.computeIfPresent(8, (integer, strings) -> {
        Set<String> set = new HashSet<>();
        set.add("888");
        return set;
    });
    
    // 遍历输出key-value映射
    map.forEach((k, v) -> System.out.println("key=" + k + " value=" + v));
    

    在使用lambda表达式时需要明白以下两点:

    • Java8为容器新增一些有用的方法,这些方法有些是为完善原有功能,有些是为引入函数式编程,学习和使用这些方法有助于我们写出更加简洁有效的代码。
    • 函数接口虽然很多,但绝大多数时候我们根本不需要知道它们的名字,书写Lambda表达式时类型推断帮我们做了一切。

    参考博文:
    (1)https://objcoding.com/2019/03/04/lambda/ (非常详细,值得仔细阅读)
    (2)https://www.runoob.com/java/java8-lambda-expressions.html

  • 相关阅读:
    MathML
    Redux counterpart rematch dva
    flow
    pauseable 库
    a simple machine learning system demo, for ML study.
    react图工具集成
    SQLite
    Celery
    RabbitMQ installation
    Thunk
  • 原文地址:https://www.cnblogs.com/jasonboren/p/13741371.html
Copyright © 2011-2022 走看看