zoukankan      html  css  js  c++  java
  • 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);
    

    总结

    在这里插入图片描述


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

    总结

    在这里插入图片描述


  • 相关阅读:
    border-radius
    border-style
    border-width
    border
    max-width
    min-width
    clip 语法
    left
    z-index
    position
  • 原文地址:https://www.cnblogs.com/PythonFCG/p/13860141.html
Copyright © 2011-2022 走看看