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

  • 相关阅读:
    HDU 1863 畅通工程(Kruskal)
    HDU 1879 继续畅通工程(Kruskra)
    HDU 1102 Constructing Roads(Kruskal)
    POJ 3150 Cellular Automaton(矩阵快速幂)
    POJ 3070 Fibonacci(矩阵快速幂)
    ZOJ 1648 Circuit Board(计算几何)
    ZOJ 3498 Javabeans
    ZOJ 3490 String Successor(模拟)
    Java实现 LeetCode 749 隔离病毒(DFS嵌套)
    Java实现 LeetCode 749 隔离病毒(DFS嵌套)
  • 原文地址:https://www.cnblogs.com/jasonboren/p/13741371.html
Copyright © 2011-2022 走看看