Java Lambda 表达式入门
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);
总结

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


 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号