从入门到入土:Lambda完整学习指南,包教包会!(中)

简介: 从入门到入土:Lambda完整学习指南,包教包会!(中)

构造器引用


构造器使用的前提是什么?


  • 构造器参数列表要与接口中抽象方法的参数列表一致!


语法格式:


  • 类名 :: new

// Employee类中必须有一个 Employee(String name, int age) 的构造器
  BiConsumer<String, Integer> biConsumer = Employee :: new;
  biConsumer.accept("王五", 19);


数组引用


数组引用和构造引用基本相同


@Test
  public void test10(){
      //传统Lambda实现
      Function<Integer,int[]> function = (i) -> new int[i];
      int[] apply = function.apply(10);
      System.out.println(apply.length); // 10
      //数组类型引用实现
      function = int[] ::new;
      apply = function.apply(100);
      System.out.println(apply.length); // 100
  }


Collections中的常用函数接口


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


Java集合框架的接口继承结构:


image.png


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



image.png


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


Collection中的新方法


forEach()


该方法的签名为void forEach(Consumer action),作用是对容器中的每个元素执行action指定的动作,其中Consumer是个函数接口,里面只有一个待实现方法void accept(T t)。


匿名内部类实现:


ArrayList<Integer> list = new ArrayList<>(Arrays.asList(3, 6, 9, 10));
  list.forEach(new Consumer<Integer>(){
      @Override
      public void accept(Integer integer){
          if(integer % 3 == 0){
              System.out.println(integer);
          }
      }
  });


lambda表达式实现:


ArrayList<Integer> list = new ArrayList<>(Arrays.asList(3, 6, 9, 10));
  list.forEach((s) -> {
      if (s % 3 == 0){
          System.out.println(s);
      }
  });


removeIf()


该方法签名为boolean removeIf(Predicate filter),作用是删除容器中所有满足filter指定条件的元素,其中Predicate是一个函数接口,里面只有一个待实现方法boolean test(T t)。


匿名内部类实现:


ArrayList<Integer> list = new ArrayList<>(Arrays.asList(3, 6, 9, 10));
  list.removeIf(new Predicate<Integer>(){ // 删除长度大于3的元素
      @Override
      public boolean test(Integer sum){
          return sum % 3 == 0;
      }
  });
  System.out.println(list);


lambda表达式实现:


ArrayList<Integer> list = new ArrayList<>(Arrays.asList(3, 6, 9, 10));
  list.removeIf(s -> s % 3 == 0);
  System.out.println(list);


replaceAll()


该方法签名为void replaceAll(UnaryOperator<E> operator),作用是对每个元素执行operator指定的操作,并用操作结果来替换原来的元素。其中UnaryOperator是一个函数接口,里面只有一个待实现函数T apply(T t)。



匿名内部类实现:


ArrayList<Integer> list = new ArrayList<>(Arrays.asList(3, 6, 9, 10));
  list.replaceAll(new UnaryOperator<Integer>(){
      @Override
      public Integer apply(Integer sum){
          if(sum % 3 == 0){
              return ++sum;
          }
          return --sum;
      }
  });
  System.out.println(list);


lambda表达式实现:


ArrayList<Integer> list = new ArrayList<>(Arrays.asList(3, 6, 9, 10));
  list.replaceAll(sum -> {
      if (sum % 3 == 0){
          return ++sum;
      }else {
          return --sum;
      }
  });
  System.out.println(list);


sort()


该方法定义在List接口中,方法签名为void sort(Comparator c),该方法根据c指定的比较规则对容器元素进行排序。Comparator接口我们并不陌生,其中有一个方法int compare(T o1, T o2)需要实现,显然该接口是个函数接口。

匿名内部类实现:


ArrayList<Integer> list = new ArrayList<>(Arrays.asList(6, 10, 9, 3));
  Collections.sort(list, new Comparator<Integer>(){
      @Override
      public int compare(Integer sum1, Integer sum2){
          return sum1 - sum2;
      }
  });
  System.out.println(list);


lambda表达式实现:


ArrayList<Integer> list = new ArrayList<>(Arrays.asList(6, 10, 9, 3));
  System.out.println(list);
  list.sort((sum1, sum2) -> sum1 - sum2);
  System.out.println(list);


spliterator()


方法签名为Spliterator<E> spliterator(),该方法返回容器的可拆分迭代器。从名字来看该方法跟iterator()方法有点像,我们知道Iterator是用来迭代容器的,Spliterator也有类似作用,但二者有如下不同:


Spliterator既可以像Iterator那样逐个迭代,也可以批量迭代。批量迭代可以降低迭代的

开销。


Spliterator是可拆分的,一个Spliterator可以通过调用Spliterator trySplit()方法来尝试分成两个。一个是this,另一个是新返回的那个,这两个迭代器代表的元素没有重叠。

可通过(多次)调用Spliterator.trySplit()方法来分解负载,以便多线程处理。


stream()和parallelStream()


stream()和parallelStream()分别返回该容器的Stream视图表示,不同之处在于parallelStream()返回并行的Stream。Stream是Java函数式编程的核心类,具体内容后面单独介绍。


Map中的新方法


forEach()


该方法签名为void forEach(BiConsumer action),作用是对Map中的每个映射执行action指定的操作,其中BiConsumer是一个函数接口,里面有一个待实现方法void accept(T t, U u)。


匿名内部类实现:


HashMap<Integer, String> map = new HashMap<>();
  map.put(1, "我");
  map.put(2, "拒绝");
  map.put(3, "996");
  map.forEach(new BiConsumer<Integer, String>(){
      @Override
      public void accept(Integer key, String value){
          System.out.println(key + "=" + value);
      }
  });


lambda表达式实现:


HashMap<Integer, String> map = new HashMap<>();
  map.put(1, "我");
  map.put(2, "拒绝");
  map.put(3, "996");
  map.forEach((key, value) -> System.out.println(key + "=" + value));


getOrDefault()


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


实现:


HashMap<Integer, String> map = new HashMap<>();
  map.put(1, "我");
  map.put(2, "拒绝");
  map.put(3, "996");
  // Java7以及之前做法
  if(map.containsKey(4)){
      System.out.println(map.get(4));
  }else{
      System.out.println("NoValue");
  }
  // Java8使用Map.getOrDefault()
  System.out.println(map.getOrDefault(4, "NoValue"));


putIfAbsent()


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


remove()


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


replace()


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


  • replace(K key, V value),只有在当前Map中key的映射存在时才用value去替换原来的值,否则什么也不做。


  • replace(K key, V oldValue, V newValue),只有在当前Map中key的映射存在且等于oldValue时才用newValue去替换原来的值,否则什么也不做。


replaceAll()


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


匿名内部类实现:


HashMap<Integer, String> map = new HashMap<>();
  map.put(1, "我");
  map.put(2, "拒绝");
  map.put(3, "996");
  map.replaceAll(new BiFunction<Integer, String, String>(){
      @Override
      public String apply(Integer k, String v){
          if (v.equals("我")){
              v = "你";
          }
          return v.toUpperCase();
      }
  });
  map.forEach((key, value) -> System.out.println(key + "=" + value));


lambda表达式实现:


HashMap<Integer, String> map = new HashMap<>();
  map.put(1, "我");
  map.put(2, "拒绝");
  map.put(3, "996");
  map.replaceAll((k, v) -> {
      if (v.equals("我")){
          v = "你";
      }
      return v.toUpperCase();
  });
  map.forEach((key, value) -> System.out.println(key + "=" + value));


merge()


该方法签名为merge(K key, V value, BiFunction remappingFunction)。


作用是:


  • 如果Map中key对应的映射不存在或者为null,则将value(不能是null)关联到key上;


  • 否则执行remappingFunction,如果执行结果非null则用该结果跟key关联,否则在Map中删除key的映射。


  • 参数中BiFunction函数接口前面已经介绍过,里面有一个待实现方法R apply(T t, U u)。


merge()方法虽然语义有些复杂,但该方法的用方式很明确,一个比较常见的场景是将新的错误信息拼接到原来的信息上,比如:


HashMap<Integer, String> map = new HashMap<>();
map.put(1, "我");
map.put(2, "拒绝");
map.put(3, "996");
map.forEach((key, value) -> System.out.println(key + "=" + value));
map.merge(1, "和你", (v1, v2) -> v1+v2);
map.forEach((key, value) -> System.out.println(key + "=" + value));


相关文章
C++ Primer Plus 第二章编程练习
C++ Primer Plus 第二章编程练习
C Primer Plus 第四章编程练习
C Primer Plus 第四章编程练习
110 0
C Primer Plus 第四章编程练习
|
安全 前端开发 Java
Kotlin Primer · 第一章 · 基础语法与面向对象思想
Kotlin Primer · 第一章 · 基础语法与面向对象思想
78 0
Kotlin Primer · 第一章 · 基础语法与面向对象思想
|
小程序 C++
C++ Primer Plus 第三章编程练习
C++ Primer Plus 第三章编程练习
C Primer Plus 第二章编程练习
C Primer Plus 第二章编程练习
78 0
C Primer Plus 第一章编程练习
C Primer Plus 第一章编程练习
93 0
C Primer Plus 第三章编程练习
C Primer Plus 第三章编程练习
64 0
|
存储 编解码 JSON
Python编程从入门到实践-读书笔记(下)
基础知识重点摘录 字符串 在Python中,用引号括起的都是字符串,其中的引号可以是单引号,也可以是双引号。这种灵活性让你能够在字符串中包含引号和撇号:
|
存储 JSON 测试技术
Python编程从入门到实践-读书笔记(上)
基础知识重点摘录 字符串 在Python中,用引号括起的都是字符串,其中的引号可以是单引号,也可以是双引号。这种灵活性让你能够在字符串中包含引号和撇号:
|
Java 编译器
从入门到入土:Lambda完整学习指南,包教包会!(上)
从入门到入土:Lambda完整学习指南,包教包会!(上)
从入门到入土:Lambda完整学习指南,包教包会!(上)
下一篇
无影云桌面