Java 8新特性:学习如何使用Lambda表达式,一看必懂

我将分为两篇系列文章来描述了使用Java 8的新特性 - lambda表达式。

目录

  • 介绍
  • 我们为什么需要lambdas?
  • Lambdas的语法
  • 功能接口
  • 方法参考
  • 构造函数参考
  • 可变范围
  • 默认方法
  • 结论

介绍

Java 8版本是当前java界流行最广的一个版本。它的主要改进是在面向对象的基础上增加了对函数式编程的支持。在本文中,我将展示lambda的基本语法,并阐释几种适用的上下文环境。

我们为什么需要lambdas?

lambda表达式是一个可以传递的代码块,允许您稍后执行它,只执行一次或多次。说到这里,你可能感觉似曾相识,看下面的这段业务场景:

我们经常自定义比较器来进行集合排序。比如现在要按字符串长度对字符串进行排序,通常做法是自定义一个 Comparator对象并传递给方法进行排序,如下:

我们编写了一段用于比较元素的代码片段,封装在自定义的Comparator里。Arrays.sort方法会在适当时机调用此代码片段,对strings数组进行排序。

那么,这个适当时机,是什么时候呢?它可能是某个界面上的一个按钮被点击时,也可能是某个新线程被启动时,像下面doWork方法被调用时:

于是,当我们想要执行此代码时,就实例化一个 MyRunner对象。然后,把实例放入线程池,或者只是启动一个新线程:

总结一下整个场景:我把一段代码块传递给某人 - 线程池,排序方法或按钮。希望在适当时机需要时,他们调用我这段代码来进行排序。

在java8以前,想要传递代码块很不容易。我们只能把代码块写在一个特殊类里,然后实例化一个类对象来传递这段代码。

在其他语言中,例如C#,则可以直接使用代码块。java语言设计者多年来一直反对添加此功能。理由无非是想要保持语法的简单性和一致性。但却牺牲了编码便利性。

在下一节中,我们一起来了解如何在Java中使用代码块。

Lambdas的语法

让我们再次回到字符串排序。我们提供了确定哪个字符串更短的代码。我们计算

这一行代码无非表达了一个意思,使用Integer.compare对 firstStr和 secondStr进入排序。

让我们用提问的方式来更明确的描述这个意思:

1、我们要处理的入参数数据是什么?是什么数据类型?

2、使用什么代码片断来对它们进行处理?

有了提问,回答就容易了。是对这样的入参数据进行处理(String firstStr, String secondStr),使用这样的 Integer.compare(firstStr.length(),secondStr.length()) 代码片断。

于是,有了我们第一个lambda表达式!此表达式指定代码块和必须传递给代码块的变量。

还有一点历史...关于lambda这个名字的来历?很久以前,在计算机还没有出世的时候,数学家Alonzo Church想要形式化数学函数有效计算的意义。(有一些已知存在的函数,但没有人知道如何计算它们的值。)他使用希腊符号lambda(λ)来标记参数。从那以后,带有参数变量的表达式被称为“lambda表达式”。

Java lambda略有几种不同的形式。让我们更仔细地考虑一下。您刚刚看到其中一个:参数, - >箭头和表达式。如果代码包含的计算不适合单个表达式,那么就像编写方法一样编写它:将代码放入{}并添加显式 return语句。例如,

如果lambda中没有参数,你仍然应该放置空括号,就像无参数方法一样:

如果可以推断lambda的参数类型,则可以省略它们。例如,

此时,编译器可以找出 firstStr并且 secondStr是字符串,因为我们将lambda分配给字符串比较器。(我们稍后会仔细研究这段代码。)

如果一个方法只有一个参数,编译器可以推导出是哪种类型,你甚至可以省略括号:

此外,您可以像 final方法参数一样,将修饰符和注释放在lambda参数中:

您永远不需要指定lambda表达式的结果类型。编译器总是从上下文中推断出它。例如,您可以使用lambda

其中 int预期作为结果类型。

请注意,在lambda中,您不能返回不在分支中的值。例如, (intx)->{if(x<=1)return-1;}无效。

功能接口

像我们文章开头讨论的那样,Java可以借用接口来封装代码块,比如 Runnable或 Comparator。这对Lambdas同样适用。

在Java中有所谓的功能接口 - 一个只有单个抽象方法实现的接口对象。只要需要功能接口的对象,就可以使用lambda表达式。

让我们考虑一下 Arrays.sort方法的例子。在这里我们可以看到用lambda替换功能接口。我们只是将lambda作为第二个参数传递给方法,该参数需要一个 Comparator对象,该接口只有一个方法。

实际上该 Arrays.sort方法接收一些类实现的对象 Comparator<String>。compare调用该方法时,它会强制执行lambda表达式主体。这些对象和类的结构完全取决于实现。它不仅可以使用传统的内部类。也许最好将lambda表示为一个函数,而不是作为一个对象,并发现我们可以将它传递给一个功能接口。

这种对接口的转换是lambda表达式令人兴奋的原因。语法简短。这是另一个例子:

是不是很易读?

事实上,你在Java中使用lambda表达式唯一能做的就是转换。

Java API中的java.util.function包中有几个通用的功能接口。其中之一, BiFunction<T,U,R>代表与参数类型的函数 T和 U和返回类型 R。您可以将字符串比较lambda传给这样的变量:

您可以在不同的Java 8 API中看到java.util.function中的这些接口。在Java 8中,任何功能接口都可以用@FunctionalInterface。这个注释是可选的,但却是一个很好的风格。首先,它强制编译器检查带注释的实体是否是具有单个抽象方法的接口。第二是告诉javadoc页面包含一个声明,这个接口是一个功能接口。根据定义,任何只有一个抽象方法的接口都是一个功能接口。但是,使用此关键字可以更加清晰。

顺便说一句,在将lambda转换为功能接口时,可能会出现已检查的异常。如果lambda表达式的主体抛出已检查的异常,则应在目标接口的抽象方法中声明此异常。例如,以下代码将导致错误:

此语句不正确,因为该 run方法不能抛出任何异常。有两种方法应对此问题。

一种方法是捕获lambda体中的异常。第二个是将此lambda分配给具有单个抽象方法的接口,该方法可以抛出异常。例如, call接口的方法 Callable可以生成任何异常。因此,如果 returnnull在lambda主体的末尾添加,则可以将lambda分配给 Callable<Void>实例。

对以上有任何疑问的都可以留言评论~

读者福利:分享一大波面试题给大家,需要的自行点击链接阅读哦!

Java面试高频题精选300道,一份通往阿里的必备指南(pdf文档)

原文地址:https://www.cnblogs.com/moon0201/p/11165566.html

时间: 2024-08-01 02:41:52

Java 8新特性:学习如何使用Lambda表达式,一看必懂的相关文章

Java8新特性学习笔记(一) Lambda表达式

没有用Lambda表达式的写法:  Comparator<Transaction> byYear = new Comparator<Transaction>() {             @Override            public int compare(Transaction o1, Transaction o2) {                return o1.getValue().compareTo(o2.getValue());             

Java8新特性小结-接口与Lambda表达式

Java8的新特性相对于前版本(Java7)来说,主要体现在两个方面: 1.   接口定义与使用 2.   Lambda表达式对匿名内部类的简化使用. Java8新特性的具体表现如下: 1.在接口中的体现 (1)在接口中可以定义实体方法,但除原先的抽象方法外只能定义两种方法: A.公共的静态方法 如: package com.jasberyon.java8.interfacer; public interface InterfaceA { public static void sayHi(){

Java8新特性Stream API与Lambda表达式详解(1)

1 为什么需要Stream与Lambda表达式? 1.1  为什么需要Stream Stream作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream.Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利.高效的聚合操作(aggr

JDK7新特性学习之 --- switch的表达式

JDK7之前,switch中表达式只能是char.byte.short.int及其对应的包装类和枚举类型.JDK7之后java中新增加了String类型作为switch的表达式之一. 但是在使用String类型作为表达式的时候,case语句有可能会出现重复的情况,例如字符串和其对应的Unicode转义字符,字面上是两个不同的字符串,但是在编译的时候,表示的都是一样的,所以会造成编译错误. 例如: /** * 会出现编译错误 */ public class Test{ public String

Java 8 新特性 – 终极手册整理

1.简介 毫无疑问,Java 8是自Java  5(2004年)发布以来Java语言最大的一次版本升级,Java 8带来了很多的新特性,比如编译器.类库.开发工具和JVM(Java虚拟机).在这篇教程中我们将会学习这些新特性,并通过真实例子演示说明它们适用的场景. 本教程由下面几部分组成,它们分别涉及到Java平台某一特定方面的内容: 语言 编译器 类库 开发工具 运行时(Java虚拟机) 2.Java的新特性 总体来说,Java 8是一个大的版本升级.有人可能会说,Java 8的新特性非常令人

Java 8新特性前瞻

快端午小长假了,要上线的项目差不多完结了,终于有时间可以坐下来写篇博客了. 这是篇对我看到的java 8新特性的一些总结,也是自己学习过程的总结. 几乎可以说java 8是目前为止,自2004年java 5发布以来的java世界中最大的事件了.它带来了java语言层面上的诸多改变,主要包括下面一些方面:语法.编译器.库.工具和运行时. 一,语法层面: 1,Lambda表达式. lambda表达式是一种可调用对象,它允许我们将函数作为函数参数传入.诸如C++.Groovy.Scala都已经支持la

Spring 4支持的Java 8新特性一览

有众多新特性和函数库的Java 8发布之后,Spring 4.x已经支持其中的大部分.有些Java 8的新特性对Spring无影响,可以直接使用,但另有些新特性需要Spring的支持.本文将带您浏览Spring 4.0和4.1已经支持的Java 8新特性. Spring 4支持Java 6.7和8 Java 8编译器编译过的代码生成的.class文件需要在Java 8或以上的Java虚拟机上运行.由于Spring对反射机制和ASM.CGLIB等字节码操作函数库的重度使用,必须确保这些函数库能理解

Java 11 新特性介绍

Java 11 已于 2018 年 9 月 25 日正式发布,之前在Java 10 新特性介绍中介绍过,为了加快的版本迭代.跟进社区反馈,Java 的版本发布周期调整为每六个月一次——即每半年发布一个大版本,每个季度发布一个中间特性版本,并且做出不会跳票的承诺.通过这样的方式,Java 开发团队能够将一些重要特性尽早的合并到 Java Release 版本中,以便快速得到开发者的反馈,避免出现类似 Java 9 发布时的两次延期的情况. 按照官方介绍,新的版本发布周期将会严格按照时间节点,于每年

spring4.0.6最新稳定版新特性学习,简单学习教程(一)

Spring Framework 4.0 学习整理. Spring框架的核心部分就是Ioc容器,而Ioc控制的就是各种Bean,一个Spring项目的水平往往从其XML配置文件内容就能略知一二,很多项目,往往是外包公司的项目,配置文件往往是乱七八糟,抱着能跑就行,不报错就行的态度去写,然后在项目中后期发现各种缺失又去一通乱补,其结果就是,整个文档可读性极差,毫无章法.这也不能怪写这个XML的人,拿着苦逼程序员的工资干着架构师的工作必然是这个结果.为了程序员的幸福,我认为有必要来一套简单快速的官方

Java 8新特性之旅:使用Stream API处理集合

在这篇“Java 8新特性教程”系列文章中,我们会深入解释,并通过代码来展示,如何通过流来遍历集合,如何从集合和数组来创建流,以及怎么聚合流的值. 在之前的文章“遍历.过滤.处理集合及使用Lambda表达式增强方法”中,我已经深入解释并演示了通过lambda表达式和方法引用来遍历集合,使用predicate接口来过滤集合,实现接口的默认方法,最后还演示了接口静态方法的实现. 源代码都在我的Github上:可以从 这里克隆. 内容列表 使用流来遍历集合. 从集合或数组创建流. 聚合流中的值. 1.