对于Java8其实相比之前的的版本增加的内容是相当多的,其中有相当一大块的内容是关于Lambda表达式与Stream API,而这两部分是紧密结合而不能将其拆开来对待的,但是是可以单独使用的,所以从学习的顺序来说首先得要学好Lambda表达式,然后再学习Stream API,最后再把这两者有机的结合起来,而这两部分涉及的知识体系又非常的多,很多东西都改变了以往对java这种面向对象语言的基本认识,所以下面一步步开始对Java8进行了解,先学好Lambda表达式。

何为Lambda表达式:

先看一个非常非常抽象的一个定义,如下:

上面看完~~可能还是一头雾水,不要着急,先对其定义有个大概的认识,重点是观注Lambda表达式是如何使用的。

为何需要Lambda表达式:

  • 在Java中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法。
    回想一下:对于java中方法的参数一定是数据类型【要么是基本数据、要么是引用数据】,同样的作为方法的返回值也只能是数据类型。但是在JDK8版本之后这些就变为可能。
  • 在JavaScript中,函数参数是一个函数,返回值是另一上函数的情况是非常常见的;JavaScript是一个非常典型的函数式语言。
    比如说举个例子:

    这个在JavaScript中是非常常见的写法。

Java匿名内部类示例:

其实上图中的这种写法是非常违背直觉的,在点击按钮的时候其实就是执行某个方法既可,但是在传统的Java编程中还得要定义一个匿名的对象实现了View.OnclickListener,可见这种写法是比较繁琐啰嗦的,而在Java8之前也只能这么去实现。

Lambda表达式初步使用:

在上面理论过后下面编写代码来一步步引出Lambda表达式,这里依然是采用Intellij IDEA来写代码,这里采用gradle的方式来编写测试代码而不用之前学习java并发的那种方式了,具体如下:

接着就进行项目的初始化,初台化完成就可以正式编写代码了,下面开始从swing代码开始,因为它有按钮的事件,跟上面说的情况类似:

编译运行:

程序比较简单,重点不是看功能,而是在于代码分析,先来仔细观察一下代码:

把鼠标放到它上面,IDE就会有提示,提示信息如下:

说明IDE都已经检测到了这个匿名内部类的写法可以改用JDK8的Lambda表达式,为什么?这个在上面也已经谈到过了,因为对于这个匿名内部类,我们所要关心的只是其回调方法中的具体实现,如下:

那改用Lambda方式来替换目前这种匿名内部类的不人性的写法是怎么样呢?照IDE的提示来做:

顺间感觉代码精简了,但是也让人对新的写法产生了各种疑问,下面写的一些代码只要感受下就行,具体Lambda表达式之后会一步步深入:

这里可以变化一下写法就能知道实际是有类型的:

而之所以直接可以将类型省略掉是由于java编译系统借助于类型推断机制能推荐出来e一定是ActionEvent类型,所以说就没有必要再去定义类型了,当然加上也没毛病,只是多此一举而已,那是不是说java8的编译系统都能够都能推荐出这个类型是什么呢?不是的,有些时候根据上下文是推断不出来的,那此时就需要显示的来指定类型的。

根据上面的Lambda表达式的写法可以总结出它的大体样式:

(param1, param2, param3...) -> {

  //执行体

}

当然关于Lambda表达式的东东不仅仅只是这点东西,之后再慢慢探究。

函数式接口(FunctionalInterface):

接下来继续举例来说明Lambda表达式,这里以集合遍历为例,从传统的方式一直演变成现在用Lambda表达式,其中会引出一个非常重要的概念---函数式接口,具体演变过程如下:

而接着在JDK1.5之后引入了增加的for循环,如下:

输出如下:

1
2
3
4
5
6
7
8
----------------------
1
2
3
4
5
6
7
8

接着到了JAVA8了,看在这个版本遍历集合有何特色:

输出:

1
2
3
4
5
6
7
8
----------------------
1
2
3
4
5
6
7
8
----------------------
1
2
3
4
5
6
7
8

其中在遍历中用到了Consumer这个接口,乍一看貌似表面上比之前的遍历方式还麻烦,不过这是暂时滴,先点进去对Consumer这个接口接口有个了解:

要了解这个注解当然是点进去进一步看一下它的源码喽:

package java.lang;

import java.lang.annotation.*;

/**
* An informative annotation type used to indicate that an interface
* type declaration is intended to be a <i>functional interface</i> as
* defined by the Java Language Specification.
*
* Conceptually, a functional interface has exactly one abstract
* method. Since {@linkplain java.lang.reflect.Method#isDefault()
* default methods} have an implementation, they are not abstract. If
* an interface declares an abstract method overriding one of the
* public methods of {@code java.lang.Object}, that also does
* <em>not</em> count toward the interface's abstract method count
* since any implementation of the interface will have an
* implementation from {@code java.lang.Object} or elsewhere.
*
* <p>Note that instances of functional interfaces can be created with
* lambda expressions, method references, or constructor references.
*
* <p>If a type is annotated with this annotation type, compilers are
* required to generate an error message unless:
*
* <ul>
* <li> The type is an interface type and not an annotation type, enum, or class.
* <li> The annotated type satisfies the requirements of a functional interface.
* </ul>
*
* <p>However, the compiler will treat any interface meeting the
* definition of a functional interface as a functional interface
* regardless of whether or not a {@code FunctionalInterface}
* annotation is present on the interface declaration.
*
* @jls 4.3.2. The Class Object
* @jls 9.8 Functional Interfaces
* @jls 9.4.3 Interface Method Body
* @since 1.8
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

关于什么是函数接口在之后还会学入学习,这里先读一读它的JavaDoc,对其有一个整体的认识,那下面就来读一读对它的描述喽:

按中文的意思来理解,也就是说明凡是一个接口上标有@FunctionalInterface注解,就可以将此接口称之为函数式接口。

光看这句话对于函数式接口还是一知半解的,那就接下来继续看下面的说明:

也就是说,如果一个接口有且只有一个抽象方法,则就可以将这个接口称之为函数式接口,这个概念在Java8的Lambda表达式出来之后是一个非常重要的概念,那看到这,一个新的疑问产生了:接口里面的方法不都是抽象的么?难道接口里面能有具体实现的方法,是的~~在java8出来之后这一切就成为可能了,当然在之前版本是不可能在接口中出现非抽象方法,所以在这句描述中就对函数式接口进行了一个基本定义,接下来继续往下看说明:

这处道出了函数式接口的非常重要的点,其中Lambda表达式我们之前已经使用过了,它可以用来创建函数式接口实例:

那其它两种创建方式具体又是什么呢?这个之后会学,先不用理会。继续往下读:

最后咱们对于这个JAVADOC的说明对其函数数接口做一个总结

1、如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口。

2、如果我们在某个接口上声明了FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口。

3、如果某个接口只有一个抽象方法,但我们并没有给该接口声明FuncationalInterface注解,那么编译器依旧依旧会将该接口看作是函数式接口。(虽这样说,但是一般对于函数式接口建议还是加上这个注解的比较好。因为加了之后编译器会对接口增加一个强制性的保证,如果接口不满足某些条件的话是会报错提示的,就这好比子类重写父类的一个特定方法的时候,照理是应该在子类的这个方法上增加一个override方法,但是如果不加也没问题,加了的好处一是代码可读性比较好,二是如果覆写了父类中并不存在的方法那么编译器会第一时间提示出来,所以最好按照规则来:如果满足函数式接口一定要在接口上声明FuncationalInterface注解)

java8学习之Lambda表达式初步与函数式接口的更多相关文章

  1. Java8(1)之Lambda表达式初步与函数式接口

    Lambda表达式初步 介绍 什么是Lambda表达式? 在如 Lisp.Python.Ruby 编程语言中,Lambda 是一个用于表示匿名函数或闭包的运算符 为何需要lambda表达式? 在 Ja ...

  2. java8学习之Lambda表达式继续探讨&Function接口详解

    对于上次[http://www.cnblogs.com/webor2006/p/8186039.html]已经初步引入的Java8中Stream流的概念,其中使用了map的操作,它需要接受一个Func ...

  3. JAVA8学习——深入浅出Lambda表达式(学习过程)

    JAVA8学习--深入浅出Lambda表达式(学习过程) lambda表达式: 我们为什么要用lambda表达式 在JAVA中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法. 在 ...

  4. Java8学习笔记----Lambda表达式 (转)

    Java8学习笔记----Lambda表达式 天锦 2014-03-24 16:43:30 发表于:ATA之家       本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人 ...

  5. java8学习之Lambda表达式深入与流初步

    Lambda表达式深入: 在上一次[http://www.cnblogs.com/webor2006/p/8135873.html]中介绍Lambda表达式的作用时,其中说到这点: 如标红处所说,既然 ...

  6. Java8学习(3)- Lambda 表达式

    猪脚:以下内容参考<Java 8 in Action> 本次学习内容: Lambda 基本模式 环绕执行模式 函数式接口,类型推断 方法引用 Lambda 复合 上一篇Java8学习(2) ...

  7. Java8新特性-Lambda表达式是什么?

    目录 前言 匿名内部类 函数式接口 和 Lambda表达式语法 实现函数式接口并使用Lambda表达式: 所以Lambda表达式是什么? 实战应用 总结 前言 Java8新特性-Lambda表达式,好 ...

  8. Java学习笔记-Lambda表达式

    Lambda表达式支持将代码块作为方法参数,Lambda表达式允许使用简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数是接口)的实例 意义 自从Java 8开始,Java支持Lambda表达 ...

  9. 怒学Java8系列一:Lambda表达式

    PDF文档已上传Github  Github:https://github.com/zwjlpeng/Angrily_Learn_Java_8 第一章 Lambda 1.1 引言 课本上说编程有两种模 ...

随机推荐

  1. 爬取汽车之家新闻图片的python爬虫代码

    import requestsfrom bs4 import BeautifulSouprespone=requests.get('https://www.autohome.com.cn/news/' ...

  2. 华三F100系列防火墙 、华为USG6300系列防火 GRE 隧道配置

    GRE概述: 通用路由封装(GRE: Generic Routing Encapsulation)是通用路由封装协议,可以对某些网络层协议的数据报进行封装,使这些被封装的数据报能够在IPV4网络中传输 ...

  3. 【并行计算-CUDA开发】CUDA shared memory bank 冲突

    CUDA SHARED MEMORY shared memory在之前的博文有些介绍,这部分会专门讲解其内容.在global Memory部分,数据对齐和连续是很重要的话题,当使用L1的时候,对齐问题 ...

  4. 【图象处理】图文详解YUV420数据格式

    转载自: http://www.cnblogs.com/azraelly/archive/2013/01/01/2841269.html YUV格式有两大类:planar和packed. 对于plan ...

  5. C学习笔记-数组

    数组的概念 数组是一组具有相同数据类型的变量集合,这里要注意两点,数组只能存储相同的数据类型和数组的内存是连续的,这位数组和指针的联系奠定了基础. 一维数组 定义及初始化 一维数组指的是只有一个下标的 ...

  6. SpringMVC 零配置 无web.xml

    对SpringMVC启动流程的讲解 https://www.cnblogs.com/beiyan/p/5942741.html 与SpringMVC的整合 https://hanqunfeng.ite ...

  7. Flume原理分析与使用案例

    1.flume的特点: flume是一个分布式.可靠.和高可用的海量日志采集.聚合和传输的系统.支持在日志系统中定制各类数据发送方,用于收集数据:同时,Flume提供对数据进行简单处理,并写到各种数据 ...

  8. Django 框架学习 ---- 安装

    这里引用了源码方式安装: 1.git clone https://github.com/django/django.git 2.cd django/ 3.python setup.py install ...

  9. [转载]Python 魔法方法详解

    据说,Python 的对象天生拥有一些神奇的方法,它们总被双下划线所包围,他们是面向对象的 Python 的一切. 他们是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个, ...

  10. 《深入理解 Java 虚拟机》学习 -- 垃圾收集器

    <深入理解 Java 虚拟机>学习 -- 垃圾收集器 1. Serial 收集器(新生代) 含义: 单线程收集器. 缺点: 进行垃圾收集时,必须暂停其他所有的工作线程. 优点: 简单而高效 ...