java8中的lambda表达式实用详解

2年前 (2022) 程序员胖胖胖虎阿
293 0 0

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

版权声明:程序员胖胖胖虎阿 发表于 2022年10月29日 下午1:08。
转载请注明:java8中的lambda表达式实用详解 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...