【JDK8新特性】Lambda 表达式和函数式接口

 
愿你如阳光,明媚不忧伤。

目録

    • 1. Lambda 表达式和函数式接口简介
    • 2. Lambda 表达式演变过程
    • 3. 带参数的 Lambda 表达式
    • 4. JDK 1.8 之前已有的函数式接口
    • 5. JDK 1.8 新增加的函数接口
    • 6. 函数式接口实例
    • 7. 自定义函数式接口
  • 【每日一面】
          • 读代码,计算打印结果

友情链接 【JDK新特性汇总】JDK8 到 JDK11 都有哪些改动

友情链接 【Class类概念】内部类,匿名类,嵌套类等解释的清晰不,铁子!

友情链接 【命运只会眷顾努力的人】泛型与序列化
 


1. Lambda 表达式和函数式接口简介

Lambda 也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中),可以使代码变的更加简洁紧凑。

Functional Interface 函数式接口,就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口(能够使用类函数做为参数)可以被隐式转换为 lambda 表达式。我们可以在任意函数式接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。

  • 语法格式(重点!!!)
    可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
    可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
    可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
    可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
() -> expression					() -> 5  			不需要参数,返回值为 5(parameters) -> expression			(x) -> 2 * x   		接收一个参数(数字类型),返回其2倍的值  
或
parameters -> expression			x -> 2 * x  		省略参数括号
或
(parameters) -> statements;			(String s) -> System.out.print(s); 		接收一个 String 对象并在控制台打印
或
parameters -> statements;			s -> System.out.print(s);				接收一个 String 对象并在控制台打印
或
(parameters) -> { statements; }		(String s) -> {System.out.print(s);System.out.print(s+"too");}		接收一个 String 对象并在控制台打印

 


2. Lambda 表达式演变过程

  • Lambda 测试阶段一
    基础版实现方法,需要单独的实现类,并在测试类中实例化。
*****************************************************************
// 测试类
public class TestLambda {

    public static void main(String[] args) {
        functionalInterface f1 = new LambdaStage1();
        f1.printInfo();
    }
}
................................................................
// 定义一个函数式接口
@FunctionalInterface
interface functionalInterface {
    void printInfo();
}
................................................................
// 实现类
class LambdaStage1 implements functionalInterface {

    @Override
    public void printInfo() {
        System.out.println("lambda test stage 1");
    }
}Console-------------------------------------------------------
lambda test stage 1
*****************************************************************
  • Lambda 测试阶段二
    静态内部类实现方法,实现类写在测试类内部,节约了一个外部类资源。
*****************************************************************
// 测试类
public class TestLambda {

    // 静态内部类
    static class LambdaStage2 implements functionalInterface {

        @Override
        public void printInfo() {
            System.out.println("lambda test stage 2");
        }
    }
................................................................
    public static void main(String[] args) {
        functionalInterface f2 = new LambdaStage2();
        f2.printInfo();
    }
}

// 定义一个函数式接口
@FunctionalInterface
interface functionalInterface {
    void printInfo();
}Console-------------------------------------------------------
lambda test stage 2
*****************************************************************
  • Lambda 测试阶段三
    局部内部类实现方法,实现类写在测试类中的方法内部,节约了一个静态内部类资源。
*****************************************************************
// 测试类
public class TestLambda {

    public static void main(String[] args) {
        // 局部内部类
        class LambdaStage3 implements functionalInterface {

            @Override
            public void printInfo() {
                System.out.println("lambda test stage 3");
            }
        }

        functionalInterface f3 = new LambdaStage3();
        f3.printInfo();
    }
}
................................................................
// 定义一个函数式接口
@FunctionalInterface
interface functionalInterface {
    void printInfo();
}Console-------------------------------------------------------
lambda test stage 3
*****************************************************************
  • Lambda 测试阶段四
    匿名内部类实现方法,没有类的名称,必须借助接口或者父类,节约了一个实现类资源。
*****************************************************************
// 测试类
public class TestLambda {

    public static void main(String[] args) {

        functionalInterface f4 = new functionalInterface() {

            @Override
            public void printInfo() {
                System.out.println("lambda test stage 4");
            }
        };
        f4.printInfo();
    }
}
................................................................
// 定义一个函数式接口
@FunctionalInterface
interface functionalInterface {
    void printInfo();
}Console-------------------------------------------------------
lambda test stage 4
*****************************************************************
  • Lambda 测试阶段五
    因为只有一个抽象方法,所以可以省去匿名类和抽象方法名,用->符号去实现。这也是 lambda 表达式必须要是函数式接口的原因。
*****************************************************************
// 测试类
public class TestLambda {

    public static void main(String[] args) {

        functionalInterface f5 = () -> {
            System.out.println("lambda test stage 5");
        };

        f5.printInfo();
    }

}
................................................................
// 定义一个函数式接口
@FunctionalInterface
interface functionalInterface {
    void printInfo();
}Console-------------------------------------------------------
lambda test stage 5
*****************************************************************
  • Lambda 测试阶段六
    回顾 Lambda 的语法格式,函数的参数类型,参数圆括号,方法体大括号以及返回的关键字都是可选的,因此还可以进一步简化。
*****************************************************************
// 测试类
public class TestLambda {

    public static void main(String[] args) {

        functionalInterface f6 = () ->
                System.out.println("lambda test stage 6");

        f6.printInfo();
    }

}
................................................................
// 定义一个函数式接口
@FunctionalInterface
interface functionalInterface {
    void printInfo();
}Console-------------------------------------------------------
lambda test stage 6
*****************************************************************

 


3. 带参数的 Lambda 表达式

  • Lambda 测试阶段七
    和上面的差不多,只不过是多了参数,Lambda 的参数类型要么都省要么都不省,不能一个省略,一个不省略。
*****************************************************************
// 测试类
public class TestLambda {

    public static void main(String[] args) {

        functionalInterface f6 = (a, b) ->
                System.out.println("lambda test stage " + a + b);

        f6.printInfo(7, "\tOuseki");
    }

}
................................................................
// 定义一个带参的函数式接口
@FunctionalInterface
interface functionalInterface {
    void printInfo(int a, String b);
}Console-------------------------------------------------------
lambda test stage 7	Ouseki
*****************************************************************

 


4. JDK 1.8 之前已有的函数式接口

  • java.lang.Runnable
  • java.util.concurrent.Callable
  • java.security.PrivilegedAction
  • java.util.Comparator
  • java.io.FileFilter
  • java.nio.file.PathMatcher
  • java.lang.reflect.InvocationHandler
  • java.beans.PropertyChangeListener
  • java.awt.event.ActionListener
  • javax.swing.event.ChangeListener

 


5. JDK 1.8 新增加的函数接口

  • java.util.function
    Consumer:消费型接口,参数 T,返回 void ;包含方法 accept(T t);
    Supplier:供给型接口,无参数,返回 T;包含方法 get();
    Function:函数型接口,参数 T,返回 R;包含方法 apply(T t);
    Predicate:断定型接口,参数 T,返回 boolean;包含方法 test(T t);
序号 接口 描述
1 BiConsumer 代表了一个接受两个输入参数的操作,并且不返回任何结果
2 BiFunction 代表了一个接受两个输入参数的方法,并且返回一个结果
3 BinaryOperator 代表了一个作用于两个同类型操作符的操作,并且返回了操作符同类型的结果
4 BiPredicate 代表了一个两个参数的boolean值方法
5 BooleanSupplier 代表了boolean值结果的提供方
6 Consumer 代表了接受一个输入参数并且无返回的操作
7 DoubleBinaryOperator 代表了作用于两个double值操作符的操作,并且返回了一个double值的结果
8 DoubleConsumer 代表一个接受double值参数的操作,并且不返回结果
9 DoubleFunction 代表接受一个double值参数的方法,并且返回结果
10 DoublePredicate 代表一个拥有double值参数的boolean值方法
11 DoubleSupplier 代表一个double值结构的提供方
12 DoubleToIntFunction 接受一个double类型输入,返回一个int类型结果
13 DoubleToLongFunction 接受一个double类型输入,返回一个long类型结果
14 DoubleUnaryOperator 接受一个参数同为类型double,返回值类型也为double
15 Function 接受一个输入参数,返回一个结果
16 IntBinaryOperator 接受两个参数同为类型int,返回值类型也为int
17 IntConsumer 接受一个int类型的输入参数,无返回值
18 IntFunction 接受一个int类型输入参数,返回一个结果
19 IntPredicate 接受一个int输入参数,返回一个布尔值的结果
20 IntSupplier 无参数,返回一个int类型结果
21 IntToDoubleFunction 接受一个int类型输入,返回一个double类型结果
22 IntToLongFunction 接受一个int类型输入,返回一个long类型结果
23 IntUnaryOperator 接受一个参数同为类型int,返回值类型也为int
24 LongBinaryOperator 接受两个参数同为类型long,返回值类型也为long
25 LongConsumer 接受一个long类型的输入参数,无返回值
26 LongFunction 接受一个long类型输入参数,返回一个结果
27 LongPredicate 接受一个long输入参数,返回一个布尔值类型结果
28 LongSupplier 无参数,返回一个结果long类型的值
29 LongToDoubleFunction 接受一个long类型输入,返回一个double类型结果
30 LongToIntFunction 接受一个long类型输入,返回一个int类型结果
31 LongUnaryOperator 接受一个参数同为类型long,返回值类型也为long
32 ObjDoubleConsumer 接受一个object类型和一个double类型的输入参数,无返回值
33 ObjIntConsumer 接受一个object类型和一个int类型的输入参数,无返回值
34 ObjLongConsumer 接受一个object类型和一个long类型的输入参数,无返回值
35 Predicate 接受一个输入参数,返回一个布尔值结果
36 Supplier 无参数,返回一个结果
37 ToDoubleBiFunction 接受两个输入参数,返回一个double类型结果
38 ToDoubleFunction 接受一个输入参数,返回一个double类型结果
39 ToIntBiFunction 接受两个输入参数,返回一个int类型结果
40 ToIntFunction 接受一个输入参数,返回一个int类型结果
41 ToLongBiFunction 接受两个输入参数,返回一个long类型结果
42 ToLongFunction 接受一个输入参数,返回一个long类型结果
43 UnaryOperator 接受一个参数为类型T,返回值类型也为T

 


6. 函数式接口实例

*****************************************************************
// 测试类
public class TestLambda {

    public static void main(String[] args) {

        IntFunction<Integer> intFunction = num -> num * 2;
        System.out.println(intFunction.apply(6));
        IntPredicate intPredicate = num -> num % 2 == 0;
        System.out.println(intPredicate.test(6));
        new TestLambda().test3();
    }
................................................................
    public void test3() {
        List<String> list= Arrays.asList("Hello","world","hi","o","123");
        List<String> filterStr = filterStr(list, (str)->str.length()>1);
        for (String string : filterStr) {
            System.out.println(string);
        }
    }
................................................................
    //需求:将满足条件的字符串,放入集合中
    public List<String> filterStr(List<String> list, Predicate<String> pre){
        List<String> list2=new ArrayList<>();

        for (String str : list) {
            if(pre.test(str)){
                list2.add(str);
            }
        }

        return list2;
    }
}Console-------------------------------------------------------
12
true
Hello
world
hi
123
*****************************************************************

 


7. 自定义函数式接口

看完上面的内置函数式接口,大家会发现其实这些接口都差不多,不同的地方就是返回类型、参数类型、参数个数。
函数式接口里是可以包含默认方法,因为默认方法不是抽象方法。
函数式接口里是可以包含静态方法,因为静态方法不能是抽象方法,必须是一个已经实现了的方法。
函数式接口里允许定义 java.lang.Object 里的 public 方法,因为任何一个函数式接口的实现,默认都继承了 Object 类,包含了来自 java.lang.Object 里对这些抽象方法的实现。

*****************************************************************
public class TestLambda {

    public static void main(String[] args) {
        CustomFunctionalInterface cf = (name, zodiac, year) -> String.valueOf("祝" + name + zodiac + "年大吉!" + year + "年生活如意,事业高升!");
        System.out.println(cf.happyNewYear("ouseki", "虎", "2022"));
    }

}
................................................................
@FunctionalInterface
interface CustomFunctionalInterface {
    String happyNewYear(String name, String zodiac, String year);

    // 可以包含默认方法
    default void defaultFunction1() {
        System.out.println("defaultFunction1");
    }

    default void defaultFunction2() {
        System.out.println("defaultFunction2");
    }

    // 可以包含静态方法
    static void staticFunction() {
        System.out.println("staticFunction");
    }

    // 允许定义 java.lang.Object 里的 public 方法
    @Override
    boolean equals(Object obj);

}Console-------------------------------------------------------
祝ouseki虎年大吉!2022年生活如意,事业高升!
*****************************************************************

 


【每日一面】

读代码,计算打印结果
d = lambda q:q*2
t = lambda t:t*3
x = 2
x = d(x)
x = t(x)
x = d(x)
print(x)

答案是:24,就是那么简单,没有弯弯绕绕。

你可能感兴趣的:(IT界大神成长之路,java,开发语言,后端)