Java8新特性 (一)Lambda

目录

前言:

这两天彻底的复习了一遍Java8的各种新特性,趁着热乎劲,把知识点整理成博客的形式保存一下。

一、Lambda介绍

Lambda表达式 : 也可称为闭包,Lambda允许把函数作为一个方法的参数(函数作为参数传递到方法中),免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力

语法格式:

(parameters) -> expression
或者
(parameters) ->{ statements; }

格式说明:
():接口中抽象方法的参数列表,没有参数就空着,有参数则写出参数,多个参数用逗号分隔
->:传递的意思,将参数传递给方法体{}
{}:重写接口的抽象方法的方法体

二、Lambda用法实例

1.简单实例(基础用法的规则)

1.1 无参数时,可以省略括号内容
()->10      //返回结果值:10
1.2 传入String类型的参数
(String s)->System.out.print(s)     //打印s的内容
1.3 传入的参数类型可以省略,如下
//
a->a*10         //返回结果值:a*10(传入一个参数时,可以省略括号)

(a,b)->a*b      //返回结果值:a*b(传入两个或以上参数时,不能省略括号,)

2.函数式接口

2.1 Lambda实现自定义接口Calculator

首先定义一个函数式接口 Calculator,包含唯一一个抽象方法 Calcu()

public interface Calculator {
    public abstract int Calcu(int x, int y);
}

其次定义一个 invokeCalcu(),接收参数类型为接口

public static void invokeCalcu(int x, int y, Calculator calculator) {
    int sum = calculator.Calcu(x, y);
    System.out.println("sum = " + sum);
}

最后调用 invokeCalcu(),一共有三种方法实现:
1)使用匿名内部类传入接口,并实现抽象方法

invokeCalcu(10, 20, new Calculator() {
    @Override
    public int Calcu(int x, int y) {
        return x + y;
    }
});

2)使用Lambda表达式,简化操作

invokeCalcu(120, 130, (a, b) -> a + b);

2.2 Lambda表达式实现多线程接口实例 Runnable
//使用匿名内部类的方式实现多线程的创建
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("currentThreadName = " + Thread.currentThread().getName());
    }
}).start();

//使用lambda表达式实现多线程
new Thread(() -> System.out.println("currentThread().getName() = " + Thread.currentThread().getName())).start();

2.3 Lambda表达式实现比较器接口实例 Comparator

定义一个Person类,保存姓名和年龄

public class Person {
    private String name;
    private int age;

    public Person() { }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() { return name; }

    public void setName(String name) { this.name = name; }

    public int getAge() { return age; }

    public void setAge(int age) { this.age = age; }
}

然后分别使用匿名内部类和Lambda表达式对Person类的年龄进行排序

Person[] arr = {
    new Person("佟丽娅", 26),
    new Person("范冰冰", 22),
    new Person("柳岩", 21)
};

//匿名内部类重写comparator接口里的compare()
System.out.println("=======匿名内部类升序排序:=================");
Arrays.sort(arr, new Comparator<Person>() {

    @Override
    public int compare(Person o1, Person o2) {
        return o1.getAge() - o2.getAge();
    }
});
for (Person person : arr) {
    System.out.println(person);
}

//使用Lambda表达式,简化匿名内部类
System.out.println("=======Lambda表达式降序排序:===============");
Arrays.sort(arr, (o1, o2) -> o2.getAge() - o1.getAge());
/**
* jdk1.8 也可以这样写  方法引用
* Arrays.sort(arr,Comparator.comparingInt(Person::getAge).reversed());
**/     
for (Person person : arr) {
    System.out.println(person);
}

//Stream API 也是Java8的新特新写法
System.out.println("=======Stream-sort升序排序:===============");
Arrays.stream(arr).sorted(Comparator.comparing(Person::getAge)).forEach(System.out::println);

接口中 有且仅有唯一一个抽象方法 ,称之为函数式接口(这种类型的接口也称为SAM接口,即Single Abstract Method interfaces)

使用前提:

  • 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法
    • 无论是 JDK内置的 RunnableComparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda
  • 使用Lambda必须具有上下文推断
    • 方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例

      有且仅有一个抽象方法的接口,称为 “函数式编程”

三、Lambda变量作用域

3.1在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量
String[] str = {"1","12","123"};  
Comparator<String> comparator = (str, second) -> Integer.compare(str.length(), second.length());  //str处的编译会出错 

3.2 Lambda 表达式只能引用标记了 final 的外层局部变量

也就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

可以直接在 lambda 表达式中访问外层的局部变量:

public static void main(String args[]) {
        final int num = 1;
        Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
        s.convert(2);  // 输出结果为 3
    }
 
    public interface Converter<T1, T2> {
        void convert(int i);
    }

lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)

int num = 1;  
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2);
num = 5;  //由于在Lambda表达式中引用了num,所以num是隐形的final修饰,但是这里修改了num的值,final就不存在了
    原文作者:中国制造
    原文地址: https://www.cnblogs.com/wuyiz/p/11863471.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞