Java8新特性, Lambda表达式与函数式接口

 

Java8的新特性有哪些

 

 

 

 

新特性的特征:

 速度更快
 代码更少(增加了新的语法:Lambda 表达式)
 强大的 Stream API
 便于并行
 最大化减少空指针异常:Optional
 Nashorn引擎,允许在JVM上运行JS应用

 

 

 

lambda表达式

 

什么是lambda表达式?

Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以
传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更 灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了
提升

 

 

为什么要有lambda表达式?

Lambda表达式。它可以让你很简洁地表示一个行为或传递代码。现在你可以把Lambda 表达式看作匿名功能,它基本上就是没有声明名称的方法,但和匿名类一样,它也可以作为参 数传递给一个方法。 

 

 

哪些场景可以使用到lambda表达式?

 

?????

 

  

 

首先我们看下再没有使用lambda的时候使用匿名内部类的对比

lambda与匿名内部类对比

  //匿名内部类
        Comparator<Integer> c1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer t1, Integer t2) {
                return Integer.compare(t1,t2);
            }
        };
        int compareNumOne = c1.compare(12,13);
        System.out.println(compareNumOne); //-1

        System.out.println("==========Lambda==========");

        // lambda表达式
        Comparator<Integer> c2 = (c3,c4) -> Integer.compare(c3,c4);
        int compareNumTwo = c2.compare(11,10);
        System.out.println(compareNumTwo); // 1

 

可以看出lambda表达式简洁了很多,直接了,不像以前这么难懂 还有一大堆的内部逻辑

 

匿名内部类

Button button = new Button("Send"); 
button.setOnAction(new EventHandler<ActionEvent>() {
  
    public void handle(ActionEvent event) {
            label.setText("Sent!!");
      }
});

 

这里,setOnAction方法的行为就用EventHandler参数化了。用Lambda表达式的话,看 起来就是这样: 

button.setOnAction((ActionEvent event) -> label.setText("Sent!!")); 

 

 

 

上面可以看出lambda使用起来很方便的  简单明了

 

lambda的使用

 

lambda的结构

 

 

 

 参数列表——这里它采用了Comparator中compare方法的参数,两个Apple。 
 箭头——箭头->把参数列表与Lambda主体分隔开。 
 Lambda主体——比较两个Apple的重量。表达式就是Lambda的返回值了。 

 

 1.举例: (o1,o2) -> Integer.compare(o1,o2);
 * 2.格式:
 *      -> :lambda操作符 或 箭头操作符
 *      ->左边:lambda形参列表 (其实就是接口中的抽象方法的形参列表)
 *      ->右边:lambda体 (其实就是重写的抽象方法的方法体)


Lambda 表达式:在Java 8 语言中引入的一种新的语法元素和操 作符。这个操作符为 “->” ,该操作符被称为 Lambda 操作符 或箭头操作符。

它将 Lambda 分为两个部分:

  左侧:指定了 Lambda 表达式需要的参数列表

  右侧:指定了 Lambda 体,是抽象方法的实现逻辑,也即 Lambda 表达式要执行的功能。

 

 

 

 

下面给出了Java 8中五个有效的Lambda表达式的例子

 

 

Lambda表达式的使用(分六种)

 

语法格式一:无参,无返回值

Runnable r1 =  () -> {System.out.println("Hello Lambda");};

r1.run();

语法格式二:Lambda需要一个参数,但是没有返回值

Consumer<String> con = (String s) -> {System.out.println(s);};

con.accept("value");

语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”

 Consumer<String> con = (s) -> {System.out.println(s);};

 con.accept("value");

语法格式四:Lambda若只需要一个参数,参数的小括号可以省略

 Consumer<String> con = s -> {System.out.println(s);};

 con.accept("value");

语法格式五:Lambda需要两个以上的参数,多条执行语句,并且可以有返回值

Consumer<Integer> con = (x,y) -> {

System.out.println(x);

return x.compareTo(y);

}

语法格式六:当Lambda体只有一条语句时,return与大括号

 Comparator<Integer> com = (o1, o2) -> o1.compareTo(o2);

 com.compreTo(10,13); 

 

 // 语法格式一:无参,无返回值
    @Test
    public void TestPOne(){
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println(" I'm one");
            }
        };
        r1.run();

        System.out.println("=======lambda======");
        Runnable r2 = () -> System.out.println("I'm lambda'One");
        r2.run();
    }


    // 语法格式二:Lambda 需要一个参数,但是没有返回值。
    @Test
    public void TestTwo(){
        Consumer<String> con1 = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con1.accept("老王");

        System.out.println("=======lambda======");
        Consumer<String> con2 = (String s1) -> {System.out.println(s1);};
        con2.accept("我是lambda老王");
    }


    //语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
    // 类型推断想我们之前遇到的泛型和数组一样
    /* Consumer<String> con = new Consumer<>();  // 省略后面的String类型
        int [] len = new int [] {1,2,3}; 可以 写成 int [] len = {1,2,3}
     */
    @Test
    public void TestThree(){
        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("老王头");

        System.out.println("=======lambda======");
        Consumer<String> con1 = (s) -> { System.out.println(s); };
        con1.accept("吾乃lambda老王头");
    }


    //语法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略
    @Test
    public void TestFour(){
        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("老刘");
        System.out.println("=======lambda======");
        Consumer<String> con1 = s -> {System.out.println(s);};
        con1.accept("吾乃lambda老刘");

    }


    //语法格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
    @Test
    public void TestFive(){
        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
        System.out.println(com.compare(13, 14));

        System.out.println("=======lambda======");
        Comparator<Integer> com1 = (l1,l2) -> {
            System.out.println(l1);
            System.out.println(l2);
            return l1.compareTo(l2);
        };
        System.out.println(com1.compare(11, 10));
    }


    //语法格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
    @Test
    public void TestSix(){

        // 原有
        Comparator<Integer> com = (o1, o2) -> {return o1.compareTo(o2);};
        System.out.println(com.compare(10, 11));

        //优化后
        Comparator<Integer> com1 = (l1, l2) -> l1.compareTo(l2);
        System.out.println(com1.compare(20, 10));

    }

 

 

由上可以看出lambda只是修改了  以前写法的方法体 方法后面的执行和参数的传递依旧时不变的  只需要看方法体怎么改变即可。

 

Summary

 * 3. Lambda表达式的使用:(分为6种情况介绍)
 *
 *    总结:
 *    ->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略
 *    ->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),省略这一对{}和return关键字
 *
 * 4.Lambda表达式的本质:作为函数式接口的实例
 *
 * 5. 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。我们可以在一个接口上使用 @FunctionalInterface 注解,
 *   这样做可以检查它是否是一个函数式接口。
 *
 * 6. 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。

 

 

 

函数式接口

 

什么是函数式接口

只包含一个抽象方法的接口,称为函数式接口。 

 

为什么要有函数式接口

Java从诞生日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP) 编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,
Java不 得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还 可以支持OOF(面向函数编程)

说白了 函数式接口就是为了让java能面向函数编程而创建的

 

函数式接口的作用

用函数式接口可以干什么呢?Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例(具体说来,是函数式接口一个具体实现 的实例)

 

   

 

 

你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式 抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽 象方法上进行声明)。 

 

 

  我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检 查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个 接口是一个函数式接口。 

  在java.util.function包下定义了Java 8 的丰富的函数式接口

   简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是 Lambda表达式和函数式接口的关系。也就是说,

    只要一个对象是函数式接口 的实例,那么该对象就可以用Lambda表达式来表示。

   所以以前用匿名实现类表  示的现在都可以用Lambda表达式来写。

 

 

 

 

自定义函数式接口

只需要在自定义的接口上加入  @FunctionalInterface 注解即可让这个接口成为函数事接口

@FunctionalInterface
public interface MyInterface {
    public void method1();
}

 

自定义函数接口与Lambda的使用

 

 

 

 

 

Java 内置四大核心函数式接口

 

 

 

其它接口

 

 

 

Lambda与函数式接口的使用

    // 根据传递参数输出信息
    public void happyTime(double money, Consumer<Double> con){
        con.accept(money);
    }


    //根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定
    public List<String> filterString(List<String> list, Predicate<String> pre){
        List<String> filterList = new ArrayList<>();
        for (String s:list
             ) {
            if(pre.test(s)){  // 如果参数s满足定义的Predicate的String泛型
                filterList.add(s);
            }
        }
        return filterList;
    }



    @Test
    public void TestMonday(){
        happyTime(500, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("去隔壁洗浴中心消费"+aDouble);
            }
        });

        System.out.println("=====lambda====");
        happyTime(4000, money -> System.out.println("买了大宝剑花费"+money));
    }

    @Test
    public void TestTuesday(){
        List<String> list = Arrays.asList("老王", "老张头","隔壁老王","隔壁小姐姐");
        List<String> list1 = filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("老"); // 包含老的字符串
            }
        });
        System.out.println(list1);


        List<String> list2 = filterString(list,s -> s.contains("老") );
        System.out.println(list2);

    }

 

 

 

 

 lambda与方法搭配使用必须满足函数式接口的要求,

 

下面既不是接口种的方法

 

 

Practices 

1:

      

 

 

 

(1) 这个Lambda没有参数,并返回void。它类似于主体为空的方法:public void run() {}。
 (2) 这个Lambda没有参数,并返回String作为表达式。
 (3) 这个Lambda没有参数,并返回String(利用显式返回语句)。
(4) return是一个控制流语句。要使此Lambda有效,需要使花括号,如下所示: (Integer i) -> {return "Alan" + i;}。 
(5)“Iron Man”是一个表达式,不是一个语句。要使此Lambda有效,你可以去除花括号 和分号,如下所示:(String s) -> "Iron Man"。或者如果你喜欢,可以使用显式返回语 句,如下所示:(String s)->{return "IronMan";}。  
View Code

 

2: 下面哪些接口是函数式接口? 

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

 public interface SmartAdder extends Adder{     
    int add(double a, double b); 
} 

public interface Nothing{ }
答案:只有Adder是函数式接口。 SmartAdder不是函数式接口,因为它定义了两个叫作add的抽象方法(其中一个是从 Adder那里继承来的)。 Nothing也不是函数式接口,因为它没有声明抽象方法。 
View Code

 

 

 

 

 

.

posted @ 2020-07-07 20:17  可爱的红领巾  阅读(1182)  评论(0编辑  收藏  举报