java8中的lambda表达式实用详解

1. lambda简介

Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。Lambda表达式是Java8中的新特性,编码一般是尽可能轻量级的将代码封装为数据,传统的解决方案是通过接口和实现类(匿名内部类)实现,这种方式存在语法冗余,this关键字,变量捕捉,数据控制等问题lambda概述

2. lambda特点

  • Lambda表达式理解为一段可以传递的代码,可以写出更简洁、更灵活的代码。
  • 使代码更简洁,紧凑
  • 可以使用并行流来并行处理,充分利用多核CPU的优势,有利于JIT编译器对代码进行优化

3. lambda经典案列

  • 线程创建的两种方式:继承Thread方式、实现Runnable方式
public interface Runnable{
void run();
}
  • 匿名内部方式创建一个线程

​Tread​​​类传递了一个匿名的​​Runnable​​​对象,重载​​Runnable​​​接口的​​run()​​方法来实现相应逻辑。

public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override //重写Runnable接口里面的run()方法
public void run() {
System.out.println("匿名内部类方式--线程1");
}
});
thread.start(); //启动线程
}
  • Lambda表达式创建一个线程
public static void main(String[] args) {
Thread thread = new Thread(
() -> System.out.println("匿名内部类方式-启动线程2"));
thread.start();
}

4.lambda语法格式

4.1 Lambda表达式的标准语法格式

Lambda表达式就是对函数式接口中抽象方法的实现,是对其匿名内部类的一个简写,只保留了方法的参数列表和方法体,其他的成分可以省略。因此,Lambda表达式的格式非常简洁,只有三部分组成:

  • 参数:指定了Lambda表达式需要的所有参数,如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
  • 箭头:由英文中画线和大于符号组成,固定写法。代表指向动作
  • 方法体:Lambda表达式要执行的功能,具体的代码方法内容
(参数,,参数)->{方法体}

基本语法:(parameters) -> expression (parameters) ->{ statements; }

注:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但无参数或多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
4.2 Lambda表达式省略语法格式

在Lambda标准语法格式的基础上,可以使用省略写法的规则:

  • 若小括号内参数只有一个可以省略。
  • 若小括号内没有参数或有两个及以上的参数,则 小括号不能省略。
  • 若大括号内只有一条语句,无论是否有返回值,大括号、return关键字、分号可以省略。
案例一:无参,无返回值,只有一条语句
public static void main(String[] args) {
Runnable runnable = () -> System.out.println("lambda 运行1");
runnable.run();
}

//结果
lambda 运行1
案例二:一个参数,无返回值
public static void main(String[] args) {
Consumer<String> consumer = (x) -> System.out.println(x);
//可简化 Consumer<String> consumer = System.out::println;
consumer.accept("lambda 运行2");
}

//结果
lambda 运行2
案例三:一个参数时,参数的小括号可以省略
public static void main(String[] args) {
Consumer<String> consumer3 = x -> System.out.println(x);
//可简化 Consumer<String> consumer3 = System.out::println;
consumer3.accept("lambda 运行3");
}

//结果
lambda 运行3
案例四:有两个参数,并且Lambda体中有多条语句。
public static void main(String[] args) {
Comparator<Integer> com4 = (x, y) -> {
System.out.println("lambda 运行4");
return Integer.compare(x, y);
};
System.out.println(com4.compare(1, 2));
}

//结果
lambda 运行4
-1
案例五:有两个以上参数,有返回值,若Lambda体中只有一条语句,return和大括号都可以省略不写
public static void main(String[] args) {
Comparator<Integer> com5 = (x, y) -> Integer.compare(x, y);
//可简化 Comparator<Integer> com5 = Integer::compare;
System.out.println(com5.compare(1, 2));
}

//结果
-1
案例六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM可以通过上下文推断出数据类型,即“类型推断”
public static void main(String[] args) {
Comparator<Integer> com = (Integer x, Integer y) -> Integer.compare(x, y);
//可简化 Comparator<Integer> com = Integer::compare;
System.out.println(com.compare(1, 2));
}

//结果
-1

**口诀:**左右遇一括号省,左侧推断类型省,能省则省。

5. 方法引用

方法引用的三种形式

  • 类 :: 静态方法
  • 类 :: 非静态方法
  • 对象 :: 非静态方法

注:

方法引用规定,对象不能调用静态方法,这和面向对象的思想一致。但类可以调用非静态方法,这是面向对象中不允许的。

5.1 类引用静态方法

语法格式:类::静态方法名

public static void main(String[] args) {
Comparator<Integer> comparable= Integer::compare;
//使用方法引用实现相同效果
Comparator<Integer> integerComparable=Integer::compare;
System.out.println(integerComparable.compare(2,1));
System.out.println(comparable.compare(2,1));
}

//结果
1
1
5.2 类引用普通方法

语法格式:类::实例方法名

public static void main(String[] args) {

BiPredicate<String, String> biPredicate = String::equals;
//使用方法引用实现相同效果
BiPredicate<String, String> bp2 = String::equals;
System.out.println(biPredicate.test("1", "2"));
System.out.println(biPredicate.test("1", "2"));
}

//结果
false
false
5.3 对象引用非静态方法

语法格式: 实例化对象::普通方法;

public static void main(String[] args) {
Consumer<String> consumer = System.out::println;
consumer.accept("java");
}

//结果
java

6. 构造引用

构造引用语法格式: 类名称::new

  • 和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
  • 抽象方法的返回值类型即为构造器所属的类的类型
//data:
public static class Employee {
private Integer id;
private String name;
private Integer age;

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

}

public Employee(Integer id) {
this.id = id;
}

public Employee(Integer id, Integer age) {
this.id = id;
this.age = age;
}

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

实例:

public static void main(String[] args) {

//原始写法
Supplier<Employee> sup = new Supplier<Employee>() {
@Override
public Employee get() {
return new Employee();
}
};

// Lambda写法
Supplier<Employee> sup1 = () -> new Employee();

//构造器引用写法
//Supplier中的T get()
//Employee的空参构造器:Employee()
Supplier<Employee> sup2 = Employee :: new;

}
// Lambda写法
Function<Integer,Employee> func1 = id -> new Employee(id);

//构造器引用写法
//Function中的R apply(T t)
Function<Integer,Employee> func2 = Employee :: new;
// Lambda写法
BiFunction<Integer,String,Employee> func1 = (id,name) -> new Employee(id,name);

//构造器引用写法
//BiFunction中的R apply(T t,U u)
BiFunction<Integer,String,Employee> func2 = Employee :: new;

7. 数组引用

数组引用的格式:type[]:new

public static void main(String[] args) {

Function<Integer,String[]> function=String[]::new;
String[] apply = function.apply(5);
System.out.println(apply.length);
}

//结果
5

8. Lambda表达式的作用域

Lambda表达式可以看作是匿名内部类实例化的对象,Lambda表达式对变量的访问限制和匿名内部类一样,因此Lambda表达式可以访问局部变量、局部引用,静态变量,实例变量。

8.1 访问局部变量

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

public static void main(String[] args) {
final int num = 1;
//不用声明为final 也可以
//int num = 1;
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);

stringConverter.convert(2);
}

//结果
3
8.2 访问对象字段,静态变量

和局部变量不同的是,Lambda内部对于实例的字段(即:成员变量)以及静态变量是既可读又可写。

import org.springframework.core.convert.converter.Converter;

public static void main(String[] args) {

Lambda4 lambda4 = new Lambda4();
lambda4.testScopes();
}


class LambdaTest {
static int myStaticNum;
int myNum;

void testScopes() {
Converter<Integer, String> stringConverter1 = (from) -> {
outerNum = 23;
return String.valueOf(from);
};
String convert = stringConverter1.convert(1);
System.out.println("Integer转化String结果" + convert);


Converter<Integer, String> stringConverter2 = (from) -> {
outerStaticNum = 72;
return String.valueOf(from);
};
String convert2 = stringConverter2.convert(2);
System.out.println("Integer转化String结果" + convert2);
}
}


//结果
Integer转化String结果 1
Integer转化String结果 2

9. 总结

java8新特性之lambda表达式知识总结的文章就介绍到这了,这边列举了部分例子供参考,仅作为学习笔记使用,欢迎批评指正,要是感兴趣可以关注微信订阅号 程序own