• Java Lambda 表达式入门


    入门

    lambda表达式最简单的作用就是用于简化创建匿名内部类对象,下面先看一下什么是命令模式

    命令模式

     命令模式简而言之就是将方法方法的具体实现分离开来,只有当调用该方法时,才确定该方法的具体实现,或者说具体行为
     下面定义一个Command接口,定义一个process方法用来封装处理行为。

    public interface Command {
        //用于封装处理行为
        void process(int element);
    }
    

     再定义一个数组处理类ProcessArray,包含一个process()方法,该方法不能确定处理数组的具体实现,所以使用了一个Command参数,通过这个参数负责处理数组的具体实现

    public class ProcessArray {
        public void process(int[] target, Command cmd){
            for(var t : target){
                cmd.process(t);
            }
        }
    }
    

     通过一个Command接口就实现了ProcessArray类与处理数组具体实现的分离。调用ProcessArray类的process方法时,处理行为是实现Command接口的对象决定的。下面用匿名内部类来实现处理数组的不同方法。

    public class CommandTest {
     public static void main(String[] args) {
            var pa = new ProcessArray();
            int[] target = {3, -4, 6, 4};
            //第一次处理数组,这里的Command 参数,使用匿名内部类传入一个对象
            pa.process(target, new Command() {
                @Override
                public void process(int element) {
                    System.out.println("数组元素的平方是:"+ element * element);
                }
            });
            //第二次处理数组
            pa.process(target, new Command() {
                @Override
                public void process(int element) {
                    System.out.println("数迭代输出数组元素:"+ element);
                }
            });
        }
    }
    

    输出结果如下图所示:
    在这里插入图片描述
    可以看到,通过匿名内部类实现了处理数组的不同效果。

    使用Lambda表达式简化创建匿名内部类对象

     上面通过命令模式这个例子引出了匿名内部类的使用,而Lambda表达式可以简化匿名内部类创建对象的过程,可以使代码更简洁。
     上面的代码片段:

     pa.process(target, new Command() {
                @Override
                public void process(int element) {
                    System.out.println("数组元素的平方是:"+ element * element);
                }
            });
    

    可以使用Lambda表达式改写为如下代码片段:

    pa.process(target, (int element) -> {
                System.out.println("数组元素的平方是:" + element * element);
            });
    

    可以看到Lambda表达式由三部分组成:

    • 形参列表: (int element)
       可以省略形参类型,如果形参列表只有一个参数则可以省略括号也可以省略,代码片段如下:
    //形参列表省略形参类型
    pa.process(target, (element) -> {System.out.println("数组元素的平方是:" + element * element);});
    //形参列表省略形参类型,一个参数可以省略括号
    pa.process(target, element -> {System.out.println("数组元素的平方是:" + element * element);});
    
    • 箭头:->
    • 代码块:{}

     只有一条语句可以省略花括号,代码片段如下所示:

    pa.process(target, element -> System.out.println("数组元素的平方是:" + element * element));
    

     只有一条return语句可以省略return,代码片段如下所示:
    先定义一个Addable接口,封装一个add方法:

    public interface Addable {
        int add(int a, int b);
    }
    

     在CommandTest类中定义一个类方法test(),调用该方法需要一个Addable对象:

    public class CommandTest {
     public static void main(String[] args) {
            var pa = new ProcessArray();
            int[] target = {3, -4, 6, 4};
            //第一次处理数组,这里的Command 参数,使用匿名内部类传入一个对象
            pa.process(target, new Command() {
                @Override
                public void process(int element) {
                    System.out.println("数组元素的平方是:"+ element * element);
                }
            });
            //第二次处理数组
            pa.process(target, new Command() {
                @Override
                public void process(int element) {
                    System.out.println("数迭代输出数组元素:"+ element);
                }
            });
            //只有一条return语句可以省略return
            test((a,b) -> a + b);
        }
     public static void test(Addable addable){
          System.out.println("5 + 3 ="+addable.add(5,3));
      }
    }
    

    总结

    在这里插入图片描述


    函数式接口

     上面的代码能正常编译,说明Lambda表达式会被当成一个任意类型的对象lambda表达式的类型被称作目标类型,其目标类型必须为函数式接口(functional interface)(只包含一个抽象方法的接口)。因为Lambda表达式的结果就是被当成对象,所以可以用来赋值。

    @FunctionalInterface
    public interface Runnable {
        void run();
    }
    

    Runnable是java本身的函数式接口,下面使用Lambda表达式创建一个Runnable对象

    
    Runnable r = () -> {
            for (var i = 0; i < 100; i++){
                System.out.println();
            }
        };
    

    总结

    在这里插入图片描述


    在Lambda表达式中使用var

     var的类型是由编译器推断的,所以使用Lambda表达式给var赋值时需要指明Lambda表达式的类型。

    //要进行强制转换指明类型
    var run = (Runnable)()->{
                for (var i = 0; i < 100; i++){
                    System.out.println();
                }
            };
    

    总结

    在这里插入图片描述


    方法引用与构造器引用

    Lambda表达式的代码块如果只有一条代码,则在代码块中可以使用方法引用构造器引用。两种引用都需要使用两个英文冒号“::”。

    • 引用类方法

     先定义一个函数式接口Converter

    @FunctionalInterface
    interface Converter{
        Integer convert(String from);
    }
    

     再使用Lambda表达式创建Converter对象,通过该对象调用convert方法

    public class MethodRefer {
        public static void main(String[] args) {
            Converter converter1 = from -> Integer.valueOf(from);
            var val = converter1.convert("99");
            System.out.println(val);
        }
    }
    

     由于converter1是由Lambda表达式创建的,所以convert()方法的执行体是Lambda表达式的代码块部分。
     上述代码块可以改写为方法引用

    //函数式接口中抽象方法的全部参数传给该类方法作为参数
    Converter converter1 = Integer::valueOf;
    
    • 引用特定对象的实例方法

     使用Lambda表达式创建Converter2对象

    Converter converter2 = from -> "abc".indexOf(from);
    var val1 = converter2.convert("c");
    

    输出2
    上述代码可以使用方法引用替换:

    Converter converter2 = "abc"::indexOf;
    var val1 = converter2.convert("c");
    
    • 引用某类对象的实例方法

     先定义一个函数式接口Mytest

    interface MyTest {
        String test(String a, int b, int c);
    }
    

    使用Lambda表达式创建Mytest对象,通过该对象调用test方法

    MyTest mt = (a, b, c) -> a.substring(b, c);
    var str = mt.test("123",1,2);
    System.out.println(str);
    

    上述代码可以使用方法引用替换:

    MyTest mt = String::substring;
    var str = mt.test("123",1,2);
    
    • 引用构造器

    先定义一个函数式接口YourTest

    interface YouTest {
        JFrame win(String title);
    }
    

    使用Lambda表达式创建YourTest对象,通过该对象调用win方法

     YouTest yt = a -> new JFrame(a);
            var jf = yt.win("window");
            System.out.println(jf);
    

    上述代码可以使用构造器引用替换:

    //函数式接口中抽象方法的全部参数传给该构造器作为参数
            YouTest yt = JFrame::new;
            var jf = yt.win("window");
            System.out.println(jf);
    

    总结

    在这里插入图片描述


    与匿名内部类的联系与区别

    总结

    在这里插入图片描述


  • 相关阅读:
    hdu 6702 ^&^ 位运算
    hdu 6709 Fishing Master 贪心
    hdu 6704 K-th occurrence 二分 ST表 后缀数组 主席树
    hdu 1423 Greatest Common Increasing Subsequence 最长公共上升子序列 LCIS
    hdu 5909 Tree Cutting FWT
    luogu P1588 丢失的牛 宽搜
    luogu P1003 铺地毯
    luogu P1104 生日
    luogu P1094 纪念品分组
    luogu P1093 奖学金
  • 原文地址:https://www.cnblogs.com/PythonFCG/p/13860141.html
Copyright © 2020-2023  润新知