对于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. 【HTML】常用的标签学习

    HTML(HyperText Markup Language )又称超文本标记语言,与一般文本文件不同的是它是由各种标签或标记组成 <标签名></标签名> .所以html的学习 ...

  2. bootstrap让footer固定在顶部和底部

    一.原理 使用fixed进行固定定位,相对于浏览器窗口进行定位,然后再设置其z-index的值即可. 二.Bootstrap中使用的类 1.顶部固定:navbar-fixed-top 2.底部固定:n ...

  3. JQuery自动填充控件:autocomplete(自己稍作了修改)

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. char、varchar、nchar、nvarchar四种类型

    char,nchar是定长,如果没达到指定的长度时将自动以英文空格在其后面填充.优势在于速度较高.varchar,nvarchar属于变长,如果没有达到指定的长度时,不会将自动以英文空格在其后面填充. ...

  5. SGI STL源码stl_vector.h分析

    前言 vector 是最常用的 C++ 容器,其动态扩容的特性是普通数组不具备的,这大大增加了编程的灵活性.虽然平时用 vector 很多,也能基本理解其原理,但无法从深层次理解.直到研读了 vect ...

  6. [转帖] 龙芯 中标麒麟的 源 以及K8S

    龙芯Mips64el平台上部署K8s https://ysicing.me/posts/mips64el-loongson-k8s/ YSICING May 29 2019   kubernetes ...

  7. PAT A1036 Boys vs Girls(25)

    AC代码 #include <cstdio> #include <algorithm> using namespace std; const int max_n = 11000 ...

  8. 版本管理工具svn(转)

    这种操作类的文章就不自己再写了,感觉浪费时间. 找了一个写的不错的文章转载. 文中流程有些变动,但是问题不大,可能是版本原因. SVN服务器的本地搭建和使用 http://www.2cto.com/o ...

  9. 合并两个排序链表——牛客offer

    题目描述: 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 解题思路: 1.一般看到合并这类的题目就会很自然的想到创建一个新的链表,然后将两个链表根据一定 ...

  10. mybatis如何接收字符串转换为date类型插入数据库

    今天遇到一个问题,先描述一下: 后台获取数据,有一个字段是时间字段,后台传过来的是字符串类型的,如:2016/11/16 10:26:17, 将该字符串放在map对象中(持久层用的是mybatis或者 ...