我的编程空间,编程开发者的网络收藏夹
学习永远不晚

java8新特性-lambda表达式入门学习心得

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

java8新特性-lambda表达式入门学习心得

定义

jdk8发布新特性中,lambda是一大亮点之一。lambda表达式能够简化我们对数据的操作,减少代码量,大大提升我们的开发效率。

Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。

Lambda表达式可以表示闭包。如果你之前了解scala和js函数式编程,将会更加快速上手和学习java8的lambda新特性。

lambda表达式的语法

Lambda表达式在Java8中引入了一个新的语法操作符号,即:->,它将Lambda表达式分为两部分。

左侧

  • Lambda表达式左侧为入参参数。

右侧

  • Lambada表示式的右侧表示执行的功能。

总结就是:

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

以下是Lambda表达式几种语法格式:

1.无参,无返回值,典型的一个例子是Runnable匿名内部类的使用。

// java 8之前的写法
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " >---Lambda");
    }
};
// 使用lambda的写法
Runnable r = () -> System.out.println(Thread.currentThread().getName() + " >---Lambda");

2.一个参数的使用

// java 8 之前的写法
Consumer<String> consumer = new Consumer<String>() {
     @Override
    public void accept(String s) {
         System.out.println(s);
       }
    };
 // Lambda表达式的写法
Consumer<String> consumer = (par)->System.out.println(par);
consumer.accept("xixi");
一个参数的小括号可以省略,简化如下:
Consumer<String> consumer = par->System.out.println(par);

3.两个参数的使用

// java 8之前的写法
Comparator<Integer> comparator = new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
       return o1.compareTo(o2);
     }
 };
 // 使用Lambda表达式的方法 ,当只有一条语句的时候,大括号和return都可以省略
  Comparator<Integer> comparator=(x,y) -> x.compareTo(y);

观察上面的代码后,我们发现使用Lambda表达式,在Lambda表达式中并没有指定入参的参数类型。这个编译和运行没有报错,这个是怎么判断出来的呢?

很简单是类型推断的作用,java8中有个很大的变化,就是类型推断,简单来说javac在编译代码时候,会根据程序的上下文来推断出Lambda表达式参数类型。

例如上文中的下面这个代码:

Comparator<Integer> comparator=(x,y) -> x.compareTo(y);

这里在编译的时候,在执行x.compareTo(y)的时候根据类型推断,因为这个接口定义数据的泛型是Intger,所以根据类型推断会自动调用Integer.compareTo方法。

为理解lambda表达式的作用,以及简化我们开发。这儿将会举个小小的例子。

需求

王小明所在的公司,每一个月都会进行薪资财务报表,王小明每一个月都会自己对员工们的薪资做统计,以了解公司财务支出和订单提成等需求。常常有做订单提成排名和总工资排名的这样的一个需求。

我们将定义以下类,来完成王小明的统计需求。

基本员工类

package com.codegeek.lambda;
import lombok.*;

@Setter
@Getter
@NoArgsConstructor
@ToString
public class Employee {
    
    private String name;
    
    private int age;
    
    private double basicSalary;

    
    private double dealTotalPrice;

    public Employee(String name, int age, double basicSalary,double dealTotalPrice) {
        this.name = name;
        this.age = age;
        this.basicSalary = basicSalary;
        this.dealTotalPrice = dealTotalPrice;
    }

    
    public Double getTotalSalary() {
        return this.basicSalary + this.dealTotalPrice * 0.04;
    }
}

现在假设在A部门有,青龙,白虎,朱雀,玄武 四个部门人员。下面是他们上个月基本薪资的情况。

Employee qingLong = new Employee("青龙", 25, 5500, 7500);
Employee baiHu = new Employee("白虎", 27, 5000, 9000);
Employee zhuQue = new Employee("朱雀", 22, 3800, 4500);
Employee xuanWu = new Employee("玄武", 24, 3300, 3300);
List<Employee> employees = Arrays.asList(qingLong, baiHu, zhuQue, xuanWu);

现在有个统计的需求是,按员工年龄从小到大排列,并获取员工姓名列表。让我们分别使用Lambda表达式和java8之前的做法。

java8之前通常的做法

// 员工列表先进行排序
employees.sort(new Comparator<Employee>() {
  @Override
  public int compare(Employee o1, Employee o2) {
     Integer age1 = o1.getAge();
     Integer age2 = o2.getAge();
     return age1.compareTo(age2);
 }
});
// 遍历排序后的列表并输出员工姓名
  for (Employee employee : employees) {
    System.out.println(employee.getName());
 }

使用Lambda的做法

employees.stream().sorted((o1, o2) -> o1.getAge().compareTo(o2.getAge()))
.forEach(o -> System.out.println(o.getName()));

看到这里我们一定知道Lambda表达式使用的方便,确实减少了很多代码的使用。

函数式接口

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

使用Lambda表达式创建该对象接口的对象,如果Lambda抛出一个受检异常,通常需要在目标接口使用@FunctionalInterface注解,来声明标记了该注解的接口是一个函数式接口。

例如:

Consumer<String> consumer = par->System.out.println(par);

就是一个典型的消费型函数式接口。

注意观察该接口的源代码,只包含一个抽象的方法的接口是函数式接口,下面andThen是一个默认方法,并不属于抽象方法。不要被迷惑了。

内建函数式的接口

jdk8中默认定义了很多函数式接口,主要使用的有下面四个。

函数式接口参数类型返回类型使用说明
Consumer<T> 消费型接口Tvoid对类型T的数据进行操作,抽象方法 void accept(T t)
Supplier 供给型接口T返回类型T的对象,抽象方法 T get();
Function<T,R> 函数型接口TR对类型T对象进行操作,返回类型R的对象,抽象方法R apply(T t)
Predicate<T> 断言型接口Tbolean对类型T对象进行操作,返回类型boolean,抽象方法boolean test(T t)

四大函数式接口的使用

public class FourFunctionsTest {

    // 消费式接口
    @Test
    public void testConsumer() {
        Consumer<Integer> consumer = x -> System.out.println(x);
        consumer.accept(1);
    }

    // 供给式接口
    @Test
    public void testSupplier() {
        Supplier<String> supplier = () -> {
            StringBuffer sb = new StringBuffer();
            return sb.append("我").append(520).append("you").toString();
        };
        System.out.println(supplier.get());
    }

    // 断言式接口
    @Test
    public void testPredicate() {
        Predicate<Long> predicate = x -> x == 1L;
        System.out.println(predicate.test(2L));
    }

    // 函数式接口
    @Test
    public void testFunction() {
        Function<Integer, Boolean> function = x -> x > 3;
        System.out.println(function.apply(4));
    }
}

自定义函数式接口

上面我们举例A部门的四个员工,找出工资大于5000的员工。

// 使用策略式接口
@FunctionalInterface // 函数式接口(检查)只能有一个抽象方法
public interface MyFilter<T> {
    
    boolean getWant(T t);
}
    
public List<Employee> needEmployee(List<Employee> employeeList, MyFilter<Employee> filter) {
   List<Employee> employees = new ArrayList<>();
     for (Employee employee : employeeList) {
        if (filter.getWant(employee)) {
            employees.add(employee);
        }
     }
      return employees;
 }
// 匿名内部类
List<Employee> employees1 = needEmployee(employees, new MyFilter<Employee>() {
  @Override
  public boolean getWant(Employee employee) {
      return employee.getTotalSalary() >= 5000;
   }
});
// 使用策略者设计模式Lambda简化
needEmployee(employees, employee -> mployee.getTotalSalary() >= 5000);

看了上面代码,如果还想简化怎么做呢?这里可以使用java 8的Stream API可以大大简化以上繁多的代码。

employees.stream().filter(e -> e.getTotalSalary() > 5000d).map(Employee::getName).forEach(System.out::println);

看到这儿,可能刚刚入门的同学会懵逼,因为上面用了Stream相关的API以及(Employee::getName)中::表示什么含义呢?别着急,慢慢往下看。

方法引用

使用操作符::将方法名和对象或者类的名字分隔开,组合有以下三种。

  • 对象::实例方法名
  • 类::静态方法
  • 类::实例方法

常见的x-> System.out.println() 等同于System.out::println。 

注意:

  • Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口抽象方法的该函数列表和返回值类型保持一致。
  • 若Lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时。可以使用 ClassName :: method

说起来比较抽象,请看下面的例子。

// 对象::实例方法
    @Test
    public void testConsumer() {
        Employee emp = new Employee();
        // 函数式接口Supplier是空参,返回是Integer类型的接口,
        // 而对应emp的实例方法getAge()刚刚好是空参且返回Integer类型的数据,符合上面注意事项1的要求
        Supplier<Integer> supplier = () -> emp.getAge();
        Supplier<Double> sup2 = emp::getSalary;
        System.out.println(supplier.get());
    }

    // 类::方法名
    @Test
    public void testSupplier() {
        Comparator<String> comparator = (x, y) -> x.compareTo(y);
        // 要求参数第一个值作为方法体的调用者,第二个参数值作为方法体的被调用者(参数)符合注意事项2的要求
        Comparator<String> compString = String::compareTo;
        System.out.println(comparator.compare("2", "3"));
        
        Comparator<Integer> com = Integer::compare;
        System.out.println(com.compare(1, 2));

        BiPredicate<String, String> predicate = String::equals;
        System.out.println(predicate.test("we", "eq"));
    }

构造器引用

这儿以函数式接口为例:可以将返回的参数R,使用构造器的构造方法。

// 当Employee有下面的构造时候
    public Employee(int age) {
        this.age = age;
    }

可构造以下这样的一个函数式接口。

Function<Integer,Employee> fun = i -> new Employee(i)
System.out.println(fun.apply(13));

// 使用构造器引用简化后:
Function<Integer,Employee> fun = Employee::new
System.out.println(fun.apply(15));

到此Lambda简单入门结束,下一篇将介绍java8新特性之Stream相关API。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

java8新特性-lambda表达式入门学习心得

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

java8新特性-lambda表达式入门学习心得

这篇文章主要介绍了java8新特性-lambda表达式入门学习心得,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-03-13

java8新特性-Stream入门学习心得

这篇文章主要介绍了java8新特性-Stream入门学习心得,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-03-13

30分钟入门Java8之lambda表达式学习

前言Google在今年发布Android N开发者预览版,一并宣布开始支持Java 8。我们终于能在Android开发中使用到Java8的一些语言特性了。目前支持: 默认方法 lambda表达式 多次注解今天我们就简要学习lambda
2023-05-31

Java8新特性-Lambda表达式详解

Java8(又称为jdk1.8)是Java语言开发的一个主要版本。Lambda表达式,也可称为闭包,它是推动Java8发布的最重要新特性。本文通过详细的代码示例介绍了Java8新特性感兴趣的朋友可以参考一下
2023-05-16

java8新特性lambda表达式的语法是什么

这篇“java8新特性lambda表达式的语法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“java8新特性lambd
2023-07-05

Java8深入学习系列(一)lambda表达式介绍

前言最近在学习java8,所以接下来会给大家介绍一系列的Java8学习内容,那么让我们先从lambda表达式开始。众所周知从java8出现以来lambda是最重要的特性之一,它可以让我们用简洁流畅的代码完成一个功能。 很长一段时间java被
2023-05-31

Java8新特性Lambda表达式的一些复杂用法总结

简介lambda表达式是JAVA8中提供的一种新的特性,它支持Java也能进行简单的“函数式编程”。 它是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一
2023-05-31

Java Lambda 表达式进阶:从入门到精通的学习之旅

Java Lambda 表达式是 Java 8 中引入的一项重要特性,它允许您使用更简洁、更具表现力的语法来编写代码。本文将带您从入门到精通地学习 Java Lambda 表达式,帮助您轻松掌握这一强大的工具。
Java Lambda 表达式进阶:从入门到精通的学习之旅
2024-02-26

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录