负一、知道啥是匿名内部类不?

要使用lambda,我觉得你至少得明白匿名内部类是个啥。“o -> o.getName”是lambda表达式,"Book::getName"也是一个lambda表达式,表达式表达式,表达的是什么呢?当你在看到这个式子的时候不懵逼吗?你好像知道要取个什么东西的名字,但是是怎么取名字的,取出来的名字怎么处理,你真的知道嘛?懵逼不,不懂匿名内部类的时候,搁我我也懵。

所以我在准备之前还要给你介绍一下lambda为何而存在,这样你才能知道在什么时候能够用它,再然后,你才能开始学习它怎么使用。

Let's start:

举个栗子,数组排序见过吧?

List<Long> num = Lists.newArrayList(1L,2L,5L,3L,4L,30L,15L,0L,8L,2L);num.sort(new Comparator<Long>() {@Overridepublic int compare(Long o1, Long o2) {return (int)(o1-o2);}});

Comparator本来是一个接口,它有一个唯一的未实现的抽象方法,那就是compare(Long o1, Long o2)这个方法。

但是你是不是发现了我既然知道我要的是这个接口(Comparator),我也不用选我要实现的哪个抽象方法(就一个compare没实现了)

——那为啥还要我特地说一声我实现的是这个接口(Comparator)的这个方法(compare(o1,o2))?嗯?

于是这帮搞语言的懒鬼决定整一个更方便写的东西。

Lambda

怎么个方便法呢?

我们先来整理一下我们写的那一堆垃圾中,有哪些是有价值的可回收垃圾

...

是不是只有一个入参、一个方法体内容,最多再有个泛型确定方法体可以调用哪些方法处理入参。

于是懒鬼们为了方便更广大的懒鬼们,说,那你们给个入参给个处理方法,剩下的我们帮你写呗

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

(o1, o2) -> o1-o2

↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

你让我这么给我就这么给呗,其他的想都不要想,分号都没得(* ̄︶ ̄)

附上最后它的模样

List<Long> num = Lists.newArrayList(1L,2L,5L,3L,4L,30L,15L,0L,8L,2L);
num.sort((o1, o2) -> (int) (o1-o2));

真·一行更比五行强?!


(以上的场景都是我yy的)

P.S.:顺便说一句,只有一个抽象方法的接口,就叫函数式接口,你要是不能判断,可以在接口前加上@FunctionalInterface注解来校验,这个注解在程序中并不会有什么具体的作用,只是会告诉编译器更严格地检查这个接口的代码,保证此接口只有一个抽象的方法。

零、唠前准备:

用到哪些实体和接口呢?

1.没事儿找事儿干类:

public class JustDoSomething {//非静态方法public int justDoSomething(Object o1, Object o2){System.out.println(-1);return -1;}//静态方法public static int justDoSomeOtherThing(Object o1, Object o2){System.out.println(-2);return -2;}
}

没了

一、lambda介绍:

1.lambda的本质是?

一个可以代替特定匿名内部类(有且只有一个未实现的抽象方法)的表达式。可以用下面的代码来说明一下

/*** 这是刚刚的排序方法*/
default void sort(Comparator<? super E> c) {Object[] a = this.toArray();Arrays.sort(a, (Comparator) c);ListIterator<E> i = this.listIterator();for (Object e : a) {i.next();i.set((E) e);}}

可以看到,在lambda出现的位置上,本来应该用一个实现了比较器接口的实现类来当作参数的,所以现在的情况就是lambda能够替代这个类。

我们再来看一个方法

Thread t = new Thread(() -> System.out.println(1));

这个线程的构造方法是

public Thread(Runnable target) {init(null, target, "Thread-" + nextThreadNum(), 0);}

那么问题来了,在sort中我lambda可以表示Comparator,在new Thread的时候我又表示Runnable了?

莫非lambda这个狗东西见人说人话,见鬼说鬼话?

没错!

lambda的类型就是所谓的“目标类型”

通俗的说,就是,只要你符合函数式接口的标准,你要啥我给啥,啥姿势都行。

2.lambda可以表示成哪些形式?

前面已经展示过lambda表达式长什么样子了,总结来说,大部分lambda表达式可以归纳为下面的形状

(参数们) -> {对参数的操作}

这种极简的表达形式,也会导致理解上的偏差,我们可以分开来进行理解:

① "(参数)"部分:参数部分的标准形式应该是(a, b, .......),如果参数只有一个,a -> {方法体}也是可以的,其他时候括号均不可省略,包括无参与复数个参数的时候,另外,如果你想要加上参数的种类也是被允许的(int a, String b, ......),但咱本来不就是学lambda来偷懒的嘛!

② "->"箭头部分:这个只要英文的就行了没啥好说的。记得指向的是方法体啊!

③ "{对参数的操作}"方法体部分:这一部分只要记住两点,第一点,只有复数条语句才需要加"{}",第二点,如果只有一条语句并且是形如"return a"这样的语句,那么连"return "都可以省略掉。(究极懒惰)

注:这里的参数为什么能这样子省略呢?是因为lambda表示的对应匿名内部类中的对应抽象方法只有一个,而编译器能够推导出来各个参数对应的类型,所以你不写也没问题的啦。

但是也不一定所有的lambda都是那个形状的啦。

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓看?↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

3.lambda的特殊形式:

如果你的表达式的方法体部分的返回值只需要调用另一个类的一个方法的返回值,同时,抽象方法的参数可以原封不动地传入调用方法中,那么你可以把lambda写成

List<Long> num = Lists.newArrayList(1L,2L,5L,3L,4L,30L,15L,0L,8L,2L);
num.sort(JustDoSomething::justDoSomeOtherThing);

这里,justDoSomeOtherThing是静态方法,所以可以直接通过类类引用,如果不是静态方法,则要先实例对象,

List<Long> num = Lists.newArrayList(1L,2L,5L,3L,4L,30L,15L,0L,8L,2L);
JustDoSomething jds = new JustDoSomething();
num.sort(jds::justDoSomething);

如果你的抽象方法是要求第一个参数传入处理对象的实例,比如这样

@FunctionalInterface
public interface Job {void doSomeJobThing(String s, int a, int b);
}

期望的实现类是这样的(调用第一个参数的方法,根据后面的参数做一些操作):

public class JobImpl implements Job{@Overridepublic String doSomeJobThing(String s, int a, int b) {return s.substring(a,b);}
}

那么,你完全可以这么写:

Job job = String::substring;

是不是快很多!不过一定要注意哦,这是对参数有要求的。↓↓↓↓

接口的抽象方法的第一个参数是提供处理方法的对象。

最后一种情况,如果你的返回值只需要一个某个类的新的实例对象:

@FunctionalInterface
public interface Job {JobImpl getInstance();
}

我懒得改名字了↓

public class JobImpl{
}

这时候就可以:

Job job = JobImpl::new;

OK,懒人助手lambda工具的使用就基本讲完了~

下面整理一下lambda和匿名内部类的区别吧!

二、lambda和匿名内部类的区别:

lambda和匿名内部类异同整理
你是谁 lambda 匿名内部类
工作量 少的一批 比左边多
this关键词 this指向外部类

this指向内部类自己

super关键词 同上 同上
可实现的接口与类 只能是函数式接口 不限于函数式接口,可以实现有多个抽象方法的接口与抽象类
是否能使用接口的的默认方法 不能使用(因为没法用this指向接口类) 可以使用(使用this关键词调用自身的方法)
对外部类成员变量的引用 引用则会给外部类的成员变量加上隐性的final关键字,对该变量再赋值则会让程序报错。(此处涉及到了闭包的概念,我会在别的笔记里说)

在@山鬼谣me的这篇文章(原文链接见文末)中指出了使用lambda可能会遇到这样的问题

假设有这么一个函数式接口:

interface Task{public void execute();
}

和这两个同名方法

public static void doSomething(Runnable r){ r.run(); }
public static void doSomething(Task a){ a.execute(); }

如果用匿名类实现Task:

// 没有歧义
doSomething(new Task() {public void execute() {System.out.println("Danger danger!!");}
});

但如果用lambda表达式:

// 存在歧义,到底调用的是Runnable重载方法还是Task重载方法
doSomething(() -> System.out.println("Danger danger!!"));

解决办法:

可以通过强制转换来解决。

doSomething((Task)() -> System.out.println("Danger danger!!"));

———————————————— 
版权声明:本文为CSDN博主「山鬼谣me」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013066244/article/details/90644711

三、写在文末(怎么三就文末了):

本文的参考学习资料大部分来自疯狂java讲义(第4版),部分来源于

http://blog.oneapm.com/apm-tech/226.html#comment

这篇文章。

顺便,diss一下这个unfriendly网站

这个辣鸡网站,互相伤害呀!

java8新特性学习笔记之唠唠“匿名内部类与lambda”相关推荐

  1. Java8新特性学习笔记

    Java8新特性学习笔记 文章目录 Java8新特性学习笔记 一.接口和日期处理 1.接口增强 1.1.JDK8以前 VS JDK8 1)接口定义: 1.2.默认方法(default) 1)默认方法格 ...

  2. java8新特性学习笔记(Lambda,stream(),filter(),collect(),map())

    文章目录 1.lambda表达式(重点) 1.需求分析 2.Lambda表达式初体验 3.Lambda的语法规则 3.1 Lambda练习1 3.1 Lambda练习2 4.Lambda表达式的原理 ...

  3. java8新特性学习笔记链接

    https://blog.csdn.net/yitian_66/article/details/81010434 转载于:https://www.cnblogs.com/wangxuekui/p/10 ...

  4. Java8新特性学习_001_(Lambda表达式,函数式接口,方法引用,Stream类,Optional类)

    目录 ■代码 ■代码运行结果 ■代码说明 ・44行:Stream的.foreach方法ー参数类型:函数式接口 ・82行:Interface中,default方法 ・92行   Stream的.max方 ...

  5. jdk7新特性学习笔记

    jdk7新特性学习笔记 从网络down了视频看,记录下学过的东西. 1.二进制字面量 JDK7开始,可以用二进制来表示整数(byte,short,int和long),语法:在二进制数值前面加 0b或者 ...

  6. JDK8新特性-学习笔记

    雀语笔记连接: https://www.yuque.com/g/u22538081/ghlpft/zcbyis/collaborator/join?token=pofOuJabmo9rgKvS# 邀请 ...

  7. Java8新特性学习记录

    前言: Java 8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级.在Java Code Geeks上已经有很多介绍Java 8新特性的文章, 例如Playing with Java ...

  8. 【转载保存】java8新特性学习

    编者注:Java 8已经公布有一段时间了,种种迹象表明Java 8是一个有重大改变的发行版. 在Java Code Geeks上已经有大量的关于Java 8 的教程了,像玩转Java 8--lambd ...

  9. C++17新特性学习笔记

    c++17最新特性笔记 1.基本语言特性 ​ 这一部分介绍了 C++17中新的核心语言特性,但不包括那些专为泛型编程(即 template)设计的特性. 结构化绑定 结构化绑定允许你用一个对象的元素或 ...

最新文章

  1. php接口调用教程,php接口调用
  2. canvas arcTo()用法详解 – CodePlayer
  3. 本文将引导你使用XNA Game Studio Express一步一步地创建一个简单的游戏
  4. 【转】面试:一个单例模式,足以把你秒成渣
  5. Python判断变量类型
  6. OpenCV文档阅读笔记-brief Creates a window官方解析及实例
  7. 算法之路——插入排序篇3:希尔排序
  8. mysql三高讲解(二):2.1 索引组织表
  9. oracle中的cursor属性有哪些,Oracle学习11:游标(cursor)--显式游标隐式游标、游标四个属性、循环遍历...
  10. 定制geojson的一些小技巧和方法
  11. CentOS 7下网络设备命名
  12. 阿里研究院安筱鹏:云计算推动企业迈向高频竞争时代
  13. orcadcapture安装_OrCAD下载
  14. regexp函数 mysql_mysql 五中的REGEXP函数_mysql
  15. mid、mif文件转shapefile、geojson等格式的数据
  16. mimo雷达虚拟阵列matlab,基于Matlab的雷达阵列天线信号的波达方向估计
  17. 基于STM32的电量采集系统
  18. 关于微信卡券网页跳转链接能力的下线
  19. xsmax无法进入dfu模式_iPhone XR/XS/XS Max 如何进入恢复模式或 DFU 模式?
  20. 《剑魂之刃》游戏破解

热门文章

  1. 聚美自建的“真品联盟”被京东捅破的窗户纸
  2. 什么是面向过程与面向对象
  3. 围观 | 互联网大厂食堂PK:工作不是重点,食堂战胜一切!
  4. 监听器(统计在线人数)
  5. 初步使用bootstrap框架
  6. 红黑树与平衡二叉树_百图详解红黑树
  7. C语言程序设计入门08——初识格式化输出1:格式化输出PI值
  8. Typora自定义样式--你值得拥有自己的styles
  9. MyBatis(一)MyBatis概述
  10. 51单片机 :5RET与RETI