20191213-Lambda

Lambda表达式

  • Lambda表达式是Java SE 8中一个重要的新特性.

  • lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。Lambda表达式还增强了集合库。

  • Java Lambda表达式的一个重要用法是简化某些 匿名内部类(Anonymous Classes)的写法 。实际上Lambda表达式并 不仅仅是匿名内部类的语法糖 ,JVM内部是通过 invokedynamic指令 来实现Lambda表达式的。

Lambda并不是内部类的语法糖

Labmda表达式不是匿名内部类的语法糖,但是它也是一个语法糖。实现方式其实是依赖了几个JVM底层提供的lambda相关api。

如果是匿名内部类的语法糖,那么编译之后会有两个class文件,但是,包含lambda表达式的类编译后只有一个文件。

Lambda表达式语法 ->

-> : 该操作符被称 为 Lambda 操作符或箭头操作符

  • 左侧:指定了 Lambda 表达式需要的所有参数
  • 右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。

基本语法格式

  /**
   * 语法格式一:无参,无返回值,Lambda 体只需一条语句。
   */
   Runnable r1=()-> System.out.println("hello");
   Thread thread=new Thread(r1);
   thread.start();

   /**
    * 语法格式二:Lambda 需要一个参数。
    */
    Consumer<String> con = (x)-> System.out.println(x);

   /**
    * 语法格式三:Lambda 只需要一个参数时,参数的小括号可以省略。
   */
   Consumer<String> con2 = x -> System.out.println(x);

  /**
   * 语法格式四:Lambda 需要两个参数,并且有返回值。
   */
  Comparator<Integer> com = (x, y) -> {
    
    
    System.out.println("函数式接口");
    return Integer.compare(x, y);
  };

 /**
 * 语法格式五:当 Lambda 体只有一条语句时,return 与大括号可以省略。
 */
  Comparator<Integer> com2 = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com = (Integer x,Integer y) -> {
    
      //Integer 类型可以省略
  System.out.println("函数式接口");
  return Integer.compare(x, y);
};

Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即 “类型推断”

-----》这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda表达式的类型依赖于上下文环境,是由编译器推断出来的。

使用Lamdba表达式的要求:

  • 必须有相应的 函数接口 :内部只有一个抽象方法的接口,这种类型的接口也称为 SAM接口 ,即Single Abstract Method interfaces

自定义函数接口

只需要编写一个只有一个抽象方法的接口即可

   // 自定义函数接口
    @FunctionalInterface
    public interface ConsumerInterface<T>{
    
    
    void accept(T t);
    }

@FunctionalInterface 可加可不加:加上该标注编译器会帮你检查接口是否符合函数接口规范

ConsumerInterface<String> consumer = str -> System.out.println(str);
consumer.accept("我是自定义函数式接口");

完整:

@FunctionalInterface
public interface ConsumerInterface<T> {
    
    
    void show(T t);

    class TestStream<T>{
    
    
        private List<T> list;
        public void  myForEach(ConsumerInterface<T> consumer){
    
    
            for(T t:list){
    
    
                consumer.show(t);
            }
        }
        public void setList(List<T> list){
    
    
            this.list=list;
        }
    }


}


public class LamdbaTest2 {
    
    
    public static void main(String[] args) {
    
    
        ConsumerInterface.TestStream<String> stream=new ConsumerInterface.TestStream<>();
        List list= Arrays.asList("11","22","33");
        stream.setList(list);
        // 使用自定义函数接口书写Lambda表达式
        stream.myForEach(s -> System.out.println(s));
    }
}

Java 内置四大核心函数式接口

Consumer 消费型接口

函数式接口 参数类型 返回类型 用途
Consumer 消费型接口 T void 对类型为T的对象应用操作,包含方法:void accept(T t)
public class LambdaTest3 {
    
    
    public static void main(String[] args) {
    
    
        LambdaTest3 lambdaTest3=new LambdaTest3();
         //Consumer<T> 消费型接口
        lambdaTest3.hello("zc",m-> System.out.println("你好:"+m));
    }

    public void hello(String st, Consumer<String> con){
    
    
        con.accept(st);
    }
}

-----》你好:zc

Supplier 供给型接口

函数式接口 参数类型 返回类型 用途
Supplier<T> 供给型接口 T 返回类型为T的对象,包含方法: T get()
public class LambdaTest3 {
    
    
    public static void main(String[] args) {
    
    
     //Function<T, R> 函数型接口:
        LambdaTest3 lambdaTest3=new LambdaTest3();
        List<Integer> numList=lambdaTest3.getNumList(2,()->(int)(Math.random()*100));
        for (Integer num : numList) {
    
    
            System.out.println(num);
        }
    }

    public List<Integer> getNumList(int num, Supplier<Integer> sup){
    
    
        List<Integer> list=new ArrayList<>();
        for(int i=0;i<num;i++){
    
    
            Integer n=sup.get();
            list.add(n);
        }
        return list;
    }
}

-----》62 48

Function<T, R> 函数型接口

函数式接口 参数类型 返回类型 用途
Function<T, R> 函数型接口 T R 对类型为T的对象应用操作,并返回结果。结果是R类的对象。包含方法:R apply(T t);

public class LambdaTest3 {
    
    
    public static void main(String[] args) {
    
    
        LambdaTest3 lambdaTest3=new LambdaTest3();
        String newStr =lambdaTest3.stringHandler("\t\t\t 这是一个函数型接口 ", (str) -> str.trim());
        //String.trim() 去掉字符串首尾的空格  
        System.out.println(newStr);
        String subStr = lambdaTest3.stringHandler("这是一个函数型接口", (str) -> str.substring(4, 7));
        System.out.println(subStr);
    }

    public String stringHandler(String str, Function<String,String> fun){
    
    
        return fun.apply(str);
    }
}

----》这是一个函数型接口 函数型

Predicate 断定型接口

函数式接口 参数类型 返回类型 用途
Predicate<T> 断定型接口 T boolean 确定类型为T的对象是否满足某约束,并返回boolean值。包含方法Boolean test(T t);
public class LambdaTest3 {
    
    
    public static void main(String[] args) {
    
    
        LambdaTest3 lambdaTest3=new LambdaTest3();
        List<String> list = Arrays.asList("Hello", "Java8", "Lambda", "www", "ok");
        List<String> stringList=lambdaTest3.filterStr(list,(s)->s.length()>3);
        stringList.forEach(System.out::println);
        }

    public List<String> filterStr (List<String> list, Predicate<String> pre){
    
    
        List<String> stringList=new ArrayList<>();
        for(String str:list){
    
    
            if(pre.test(str)){
    
    
                stringList.add(str);
            }
        }
        return stringList;
    }
}

----》Hello Java8 Lambda

其他接口

函数式接口 参数类型 返回类型 用途
BiFunction<T,U,R> T,U R 对类型T,U参数应用操作,返回R类型的结果。包含方法R apply(T t,U u)
UnaryOperator<T> T T 对类型为T的对象进行一元运算,并返回T类型的结果。包含方法 T apply(T t);
BinaryOperator<T>(BiFunction子接口) T,T T 对类型为T的对象进行二元运算,并返回T类型的结果。包含方法 T apply(T t1,T t2);
BiConsumer<T,U> T,U void 对类型为T,U参数应用操作。包含方法为 void accept(T t,U u)
TolntFunction<T> ToLongFunction<T> ToDoubleFunction<T> T int long double 分别计算 int \long\double值得函数
IntFunciton<R> LongFunction<R> DoubleFunction<R> int\long\double R 参数分别为int\long\double类型得函数

方法引用和构造器引用

方法引用

使用操作符 “::” 将方法名和对象或类的名字分隔开来

前提条件:

  • 方法引用所引用的方法的 参数列表 必须要和函数式接口中抽象方法的参数列表相同(完全一致)。
  • 方法引用所引用的方法的的 返回值 必须要和函数式接口中抽象方法的返回值相同(完全一致)。

方法引用的格式:

  • 实例对象名::实例方法名
  • 类名::静态方法名
  • 类名::实例方法名

2和3的区别:若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式:类名::实例方法名。

1、对象::实例方法

  public void test1(){
    
    
        PrintStream ps =System.out;
        Consumer<String> con=(str)->ps.println(str);
        con.accept("Hello World!");
        System.out.println("--------------------------------");
        Consumer<String> con2=ps::println;
        con2.accept("con2");
        System.out.println("--------------------------------");
        Consumer<String> con3=System.out::println;
        con3.accept("con3");
    }

    public static void main(String[] args) {
    
    
        LambdaTest4 lambdaTest4=new LambdaTest4();
        lambdaTest4.test1();
    }

—》

Hello World!

con2

con3

public class LambdaTest4 {
    
    

    public void test2(){
    
    
        Employee emp=new Employee(1,"cc",18,5112.99);

        Supplier<String> sup=()->emp.getName();
        System.out.println(sup.get());

        System.out.println("----------------------------------");

        Employee emp1 = new Employee(2, "bb", 18, 5112.99);
        Supplier<String> sup2 = emp1::getName;
        System.out.println(sup2.get());
    }

    public static void main(String[] args) {
    
    
        LambdaTest4 lambdaTest4=new LambdaTest4();
        lambdaTest4.test2();
    }
}

----》

cc

bb

2、类::静态方法

public class LambdaTest4 {
    
    
 
    public void test3(){
    
    
        BiFunction<Double,Double,Double> fun=(x,y)->Math.max(x,y);
        System.out.println(fun.apply(1.5,22.2));
        System.out.println("-------------------------test3-------------------------");
        BiFunction<Double,Double,Double> fun2=Math::max;
        System.out.println(fun2.apply(1.2,1.5));
    }
    public static void main(String[] args) {
    
    
        LambdaTest4 lambdaTest4=new LambdaTest4();
        lambdaTest4.test3();
    }
}

----》

22.2

-------------------------test3-------------------------

1.5

  public void test4(){
    
    
        /**
         * Integer.compare()
         * 对象大于目标参数,返回1 
         * 对象小于目标参数,返回-1 
         * 对象等于目标参数,返回0
         */
        Comparator<Integer> com=(x,y)->Integer.compare(x,y);
        System.out.println(com.compare(3,9));
        System.out.println("-------------------------test4-------------------------");
        Comparator<Integer> com2=Integer::compare;
        System.out.println(com2.compare(3,9));
    }
    public static void main(String[] args) {
    
    
        LambdaTest4 lambdaTest4=new LambdaTest4();
        lambdaTest4.test4();
    }

—》 -1 -1

3、类::实例方法

   public void test5(){
    
    
        BiPredicate<String,String> bp=(x,y)-> x.equals(y);
        System.out.println(bp.test("abcde", "abcde"));
        System.out.println("-----------------------------------------");
        BiPredicate<String, String> bp2 = String::equals;
        System.out.println(bp2.test("abc", "abc"));
   
    public static void main(String[] args) {
    
    
        LambdaTest4 lambdaTest4=new LambdaTest4();
        lambdaTest4.test5();
    }

—》 true true

构造器引用

前提条件:

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

构造器引用的格式:

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

数组引用

public class LambdaTest5 {
    
    
    public void test(){
    
    
        //传统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
    }

    public static void main(String[] args) {
    
    
        LambdaTest5 lambdaTest5=new LambdaTest5();
        lambdaTest5.test();
    }
}

Collections中的常用函数接口

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

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

在这里插入图片描述

Collection中的新方法

forEach()
  • 该方法的签名为void forEach(Consumer action)
  • 作用是对容器中的每个元素执行action指定的动作
  • 其中Consumer是个函数接口,里面只有一个待实现方法void accept(T t)
 public static void main(String[] args) {
    
    
        //匿名内部类实现:
        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);//3,6,9
                }
            }
        });
        
        //Lambda实现:
        list.forEach((s) -> {
    
    
            if (s % 3 == 0) {
    
    
                System.out.println(s);//3,6,9
            }
        });
    }
removeIf()
  • 该方法签名为boolean removeIf(Predicate filter)
  • 作用是删除容器中所有满足filter指定条件的元素
  • 其中Predicate是一个函数接口,里面只有一个待实现方法boolean test(T t)
		//匿名内部类实现:
        ArrayList<Integer> list2 = new ArrayList<>(Arrays.asList(3, 6, 9, 10));
        list2.removeIf(new Predicate<Integer>() {
    
    
            @Override
            public boolean test(Integer sum) {
    
    
                return sum % 3 == 0;
            }
        });
        System.out.println(list2);//[10]
        
          //lambda实现:
        list2=new ArrayList<>(Arrays.asList(3, 6, 9, 10));
        list2.removeIf(s -> s % 3 == 0);
        System.out.println(list2);//[10]
replaceAll()

从入门到入土:Lambda完整学习指南,包教包会!:https://mp.weixin.qq.com/s/ogcRRWBE8CtOY5l6kcQvhg

猜你喜欢

转载自blog.csdn.net/fggsgnhz/article/details/103539454