• 【Java进阶】01 Lambda 使用与进阶


    Lambda 表达式




    初识 Lambda


    • 什么是 Lambda 表达式?

      • 自 Java 8 增加的新特性
      • 一个匿名方法(一个没有名字的方法,在定义变量的时候定义的方法)
    • 为什么使用 Lambda

      • 简洁实现接口对接;

      • 虽然可以使用 Lambda 表达式对某些接口进行实现,但是并不是所有的接口都可以使用 Lambda 来实现;

      • 实现要求:要实现的抽象方法只能是一个;

      • 在 Java 8 中对接口实现了一个新特性 default ,被此方法修饰的方法在类中有一个默认实现,所以不影响使用 Lambda 的实现;

    • @FunctionalInterface

      • 一个用来修饰函数式接口的,接口中的抽象方法只能有一个;
        // 错误代码展示
        @FunctionalInterface
        interface Comparer{
            int compare(int a,int b);// 方法一
            int show(int a,int b);	 // 方法二
        }
    
    <font color=red size=2>↑ ↑ ↑ 错误代码展示 ↑ ↑ ↑</font>
    
    public class DEMO{
       public static void main(String[] args){
           // 方法一:使用接口实现类
           Comparator comparator = new MyComparator();
           
           //方法二:使用匿名内部类
           Comparator comparator = new Comparator(){
               @Override
               public int compare(int a,int b){
                   return a-b;
               }
           }
           
           //方法三:使用Lambda表达式
           Comparator comparator2 = (a,b) -> a-b;
       }
    }
    
    // 一个接口
    interface Comparator{
       int compare(int a,int b);
    }
    
    //方法一:使用实现类实现接口
    class MyComparator implements Comparator{
       @Override
       public int compare(int a,int b){
           return a-b;
       }
    }
    



    Lambda 基础语法


    • 基础语法:

      • Lambda 是一个匿名函数
      • 包含:参数列表、方法体、(不包含:返回值类型、方法名)
    • 元素:

      • ():用来描述参数列表
      • {}:用来描述方法体
      • ->:分隔 Lambda 运算法,读作:goes to
    • 几种情况:

    1、无参  无返回

    // 无参 无返回
    LambdaTest lam1 = ()->{
     Sout("Hello World!");
    }
    lam1.test();
    // 结果:输出`Hello World!`
    

    2、单个参 无返回

    // 无参 单个返回值
    LambdaTest lam2 = (int a)->{
     Sout(a);
    }
    lam2.test(10);
    // 结果:输出`10`
    

    3、多个参 无返回

    LambdaTest lam3 = (int a,int b)->{
     Sout(a+b);
    }
    lam3.test(10,11);
    // 结果:输出`21`
    

    4、无参 有返回

    LambdaTest lam4 = ()->{
     Sout(100);
     return 100;
    }
    int ret = lam4.test();
    // 结果:输出`100` ; 返回 `100`
    

    5、有参数 有返回

    LambdaTest lam5 = (int a)->{
     Sout(a*2);
     return a*2;
    }
    int ret = lam5.test(10);
    // 结果:输出`20` ; 返回 `20`
    

    ↑ ↑ ↑ 要注意 一定要定义相应的 函数式接口 ↑ ↑ ↑




    Lambda 语法精简


    • 错误代码演示:
    interface Lamx{
        int test(int a,int b);
    }
    
    Lamx lamx = (int a,int b)->{
        Sout("a=" + a + "\nb=" + b);
        // return a+b;
    }
    

    上面报错了?Lambda表达式如何知道有返回值?

    Lambda 因为定义的接口有了说明,比如接口中写int test(int a);第一个int表示返回值类型,第二个int 表示参数类型,所以 舍去了 return 就会报错;

    既然在定义接口的时候已经定义了类型,那么是不是可以在写入参数的时候,将参数类型描述给省略掉呢?

    • 精简1:省略参数描述int

      代码演示:

    interface Lamx{
        int test(int a,int b);
    }
    
    Lamx lamx = (a,b)->{
        Sout("a=" + a + "\nb=" + b);
        return a+b;
    }
    

    接口中已经说明了有int类型的返回值,所以不写return是错误的;

    两个必须同时省略,不能一个写一个不写;

    • 精简2:省略小括号()

      代码演示:

    interface Lamx{
        int test(int a);
    }
    
    Lamx lamx = a -> {
        Sout("a=" + a );
        return a;
    }
    

    当 入参 只有一个的时候,可以省略入参的 括号;

    • 精简3:省略大括号{}
    interface Lamx{
        int test(int a);
    }
    
    Lamx lamx = a -> Sout( a );
    

    当 函数 只有一行的时候,可以省略大括号;

    • 精简4:省略return
    interface Lamx{
        int test(int a);
    }
    
    Lamx lamx = a -> a;
    

    如果唯一一条语句是return语句,那么省略大括号的同时,也必须省略return

    Lamx lamx = (a,b)->a+b;
    lamx.test(5,10);
    




    Lambda 语法进阶


    • Lambda 调用静态方法
      • 代码示例:
    public class Test{
        public static void main(String[] args){
            // 实现方式一: 传统 Lambda 语法
            Lamx lamx = a -> change(a);
            // 实现方式二: 双" : "语法
            Lamx lamx = Test::change;
        }
        
        public static int change(int a){
            return a*2;
        }
    }
    

    将 Lambda 指向一个已经实现的方法;语法规则 -- 方法隶属者::方法名

    此处的change是一个静态方法,隶属者就是Test类,所以就是Test::change

    • 注意事项:
      • 参数的数量和类型一定要和方法中定义的一致
      • 返回型一定要和接口中定义的方法一致

    • Lambda 调用构造方法
      • 保留
    // 构造方法
    public class Person{
        public String name;
        public int age;
        
        public Person(){
            Sout("Person类的 无参 构造方法执行了;");
        }
        
        public Person(String name,int age){
            this.name = name;
            this.age  = age;
            Sout("Person类的 有参 构造方法执行了;");
        }
    }
    
    // Lambda 语法
    public class Lamx{
        public static void main(String[] args){
            // 原始方法
            PersonCreater creater1 = () -> {
                return new Person();
            };
            
            // 简化方法
            PersonCreater creater2 = () -> new Person();
            
            // 构造方法的引用
            PersonCreater creater3 = Person::new;
            Person a = creater3.getPersonNull();
            Person a = creater3.getPersonDouble("张三",18);
        }
    }
    
    //接口中要说明 返回值类型 方法参数!!!
    interface PersonCreater{
        Person gerPersonNull();
        Person getPersonDouble(String name,int age);
    }
    

    实现语法 -- 类::new




    Lambda 实现实例


    1、已知在一个 ArrayList 类中有若干个 Person 对象,讲这些Person对象按照年龄进行降序排序;

    public class Exercise{
        public static void main(String[] args){
            ArrayList<Person> list = new ArrayList<>();
            list.add(new Person("张三",12));
            list.add(new Person("李四",13));
            list.add(new Person("韩梅梅",16));
            list.add(new Person("赵四",6));
            list.add(new Person("尼古拉斯凯奇",46));
            list.add(new Person("Tony",54));
            
            list.sort((o1,o2)-> o2.age-o1.age);
        }
    }
    

    2、使用TreeSet排序

    TreeSer<Person> set = new TreeSer<>((o1,o2)->o2.age-01.age);
    set.add(new Person("xiaoming",10));
    set.add(new Person("wanggang",11));
    set.add(new Person("zhaosi",8));
    set.add(new Person("Nigu",43));
    set.add(new Person("Tony",22));
    set.add(new Person("poily",8));
    set.add(new Person("Wngffei",40));
    Sout(set);
    //运行结果:基本正确,但是只有一个8岁的人;
    

    代码优化

    TreeSer<Person> set = new TreeSer<>((o1,o2)->{
        if(o1.age >= o2.age){
            retrun -1;
        }else{
            return 1;
        }
    });
    set.add(new Person("xiaoming",10));
    set.add(new Person("wanggang",11));
    set.add(new Person("zhaosi",8));
    set.add(new Person("Nigu",43));
    set.add(new Person("Tony",22));
    set.add(new Person("poily",8));
    set.add(new Person("Wngffei",40));
    Sout(set);
    //运行结果:正确;
    

    public static void main(String[] args){
        ArrayList<Interger> list -= new ArrayList<>();
        Collection.addAll(list,1,2,3,4,5,6,7,8,9,0);
        list.forEach(ele->{
            if(ele%2 == 0)
                Sout(ele);
        });
    }
    



    使用 Lambda 实现线程的实例化

    实现线程的实例化;


    public static void main(String[] args){
        Thread t = new Thread(()->{
            for(int i=0;i<100;i++){
                Sout(i);
            }
        });
        t.start();
    }
    



    系统内置的函数式接口


    public static void (String[] args){、
        //最常用的是Predicate、Consumer、Function、Supplier
        
        // Predicate<T>		:	参数T ·返回值 boolean
        //	IntPredicate	:	int-> boolean
        //	LongPredicate	:	long->boolean
        //	DoublePredicate	:	double
        
        // Consumer<T>		:	参数T ·返回值 void
        // 	IntConsumer		:	int ->void
        // 	LongConsumer
        // 	DoubleConsumer
        
        // Function<T,R>	:	参数T ·返回值 R
        //	IntFuncation	:	int->R
        //	LongFunction
        //	DoubleFunction
        //	IntToLongFunction:	int->long
        //	IntToDoubleFunction
        //	LongToIntFunction
        //	LongToDoubleFunction
        //	DoubleToIntFunction
        //	DoubleToLongFunction
        
        // Supplier<T>		:	参数无 ·返回值 T
     	//	……省略好多好多   
        // UnaryOperator<T>	:	参数T	 ·返回值T
        // BinaryOperator	:	参数T,T ·返回值T
        // BiFunction<T,U,R>:	参数T,U ·返回值R
        // BiPredicate<T,U>	:	参数T,U ·返回值boolean
        // BiConsumer<T,U>	:	参数T,U ·返回值void
    }
    



    闭包问题


    • 什么是闭包
      • 闭包会提升变量的生命周期,这样就可以获取某一个方法中的局部变量
    public static void main(String[] args){
        int n = getNum().get();
        Sout(n);
        //结果是10;
    }
    
    private static Supplier<Integer> getNum(){
        int num = 10;
        
        return ()->{
            return num;
        };
    }
    

    代码二:

    PSVM(String[] args){//public static void main
        int a = 10;
        
        Consumer<Integer> c = ele->{
            Sout(a+1);
        };
        
        c.accept(1);// 结果11
        
            Consumer<Integer> c = ele->{
            Sout(a++);
        };
        
        c.accept();// 结果报错,因为 闭包 中的变量必须是 final 的(也就是一个常量),所以不能修改这个值
    }
    
  • 相关阅读:
    NHibernate版本不一致问题
    .NET中AOP的几种实现方案
    转播
    看来不得不来谈谈这个首页精华区了
    事件与委托
    关于字符集和字符编码以及代码页的前前后后(续)
    让电脑像人脑一样思考,谁养鱼问题断言推理解法
    关于那个脑袋的很漂漂的图形的C#版本
    大家都有头像,我来测试下我的新头像。
    浅谈JavaScript中的对象和类型(上)
  • 原文地址:https://www.cnblogs.com/hskcool/p/14221510.html
Copyright © 2020-2023  润新知