第三章:lambda表达式

什么是lambda表达式

可传递匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型、可能还有一个异常列表
匿名——他没有明确的名称
函数——他不像方法那样属于某个特定的类
传递——可以作为参数传递给方法或存储在变量中
简洁——无需像匿名类一样写很多模板代码


Lambda函数组成.png

函数式接口

public interface Predicate {
    boolean test(Apple apple);
}

只定义了一个抽象方法的接口

函数式接口的作用
lambda表达式可以让你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实力

函数描述符

() -> void 描述lambda表达式的类型
@FunctionalInterface表示接口会设置成函数式接口

lambda环绕执行模式

资源处理时总是要打开资源,然后做一些处理,然后关闭资源。这个设置和清理阶段总是很类似,并且会围绕着执行处理的那这些重要代码,这就是所谓的环绕执行模式
文件中读取一行

public static String processFile() throws IOException{
        try (BufferedReader br = 
                     new BufferedReader(new FileReader("data.txt"))){
            return br.readLine();
        }
    }

这段代码只能读取文件的第一行,如果你想返回头两行,甚至是返回使用最频繁的词,该怎么办?在理想的情况下,你要重用执行设置和清理代码,并告诉
processFile方法对文件执行不同的操作。这样看就很眼熟,你需要吧processFile的行为参数话。你需要一种吧行为传递给processFile,以便他可以利用BufferReader执行不同的行为

改造这个函数使行为参数化
1,构造一个(BufferedReader br) -> String的函数描述

    @FunctionalInterface
    public interface BufferedReaderProcessor{
        String process(BufferedReader br) throws IOException;
    }

2,改造函数

    public static String processFile(BufferedReaderProcessor processor) throws IOException{
        try (BufferedReader br =
                     new BufferedReader(new FileReader("data.txt"))){
            return processor.process(br);
        }
    }

3,将lambda表达式传入函数中

 String result = processFile((BufferedReader br) -> br.readLine() + br.readLine());

实现了读取两行

使用函数式接口

函数式接口的抽象方法签名成为函数描述符
Java8库啥急事帮我们在java.util.function包中引入了几个新的函数式接口

Prediate函描述符 T -> boolean

Consumer函数描述符 T -> void

Function函数描述符 T -> R

Supplier函数描述符 () -> T

UnaryOperator函数描述符 T -> T

BinaryOperator函数描述符 (T,T) -> T

BiPredicate函数描述符 (L,R) -> boolean

BiConsumer函数描述符(T,U) -> void

BiFunction函数描述符(T,U) -> R

原始类型特化

为了减少拆箱,java8还提供了不是引用类型的函数式接口,还有很多

IntPredicate int -> boolean

异常

任何函数式接口都不可以抛出受检异常,如果你需要lambda表达式抛出异常,有两种办法
1,顶一个自己的函数式接口
2,把lambda表达式包在一个try/catch中

Lambda类型检查

lambda类型是从上下文推断出来的

同样的Lambda不同的函数式接口

是要抽象方法签名相同就可以使用同一个lambda

菱形运算
利用泛型推断出类型

特殊的void兼容规则
如果一个lambda主体是一个语句表达式,它就和一个返回void的函数描述符兼容

类型推断

Java编译器会从上下文推断出用什么函数接口来配合lambda表达式,可以推断出适合的签名

 processFile(br  -> br.readLine() + br.readLine());

使用局部变量

lambda可以使用自由变量(不是参数,而是外层作用域中定义的变量),就像匿名类一样,被称为捕获lambda

        int i = 1000;
        Runnable runnable = () -> System.out.println(i);

对变量的限制。lambda可以引用实例变量和静态变量。但局部变量必须显示声明为final,或事实上是final。换句话说,lambda表达式只能捕获指派给他的局部变量一次。(捕获实例变量可以被看做捕获最终变量this)。下面这段代码就是错误的

        int i = 1000;
        Runnable runnable = () -> System.out.println(i);
        i= 20000;//lambda表达式引用局部变量需要声明为final或者事实是final的,所以不能修改

为什么对局部变量限制
1,实例变量和局部变量背后的实现有一个关键不同。实例变量存储在对中,局部变量存储在栈中,如果lambda可以直接访问局变量,而且lambda是在一个线程中使用,则使用lambda的线程,可能会在分配该变量的线程将这个变量收回之后,去访问该变量,因此,java在访问自由局部变量时,实际上是在访问它的副本,而不是访问原始变量,如果局部变量仅仅赋值一次就没有什么区别了
2,这一限制不鼓励你使用改变外部变量的典型命令编程模式(阻碍很容易做到的并且处理)

闭包

闭包就是一个函数的实例,且他可以无限制的访问那个函数的非本地变量

方法引用

让你可以重复使用现有的方法定义,并像lambda一样传递他们

 lists.sort(Comparator.comparing(Apple::getWeight));

如何构建方法引用
1,指向静态方法的方法引用
2,指向任意类的实例方法的方法引用
3,指向现有对象实例方法的方法引用

构造函数引用

Classname::new

        Supplier<Apple> c1 = Apple::new;
        Apple a1 = c1.get();

等价于

        Supplier<Apple> c1 = () -> new Apple();
        Apple a1 = c1.get();

复合lambda表达式的有用方法

比较器复合Comparator
1,逆序

 lists.sort(Comparator.comparing(Apple::getWeight).reversed());

2,比较链

lists.sort(Comparator.comparing(Apple::getWeight).reversed().thenComparing(Apple::getColor));

谓词复合Predicate
negate 非
or 或
and 并且
函数复合Function

andThen
一个函数是f(x)一个函数是g(x),andThen后执行 g(f(x))
compose
一个函数是f(x)一个函数是g(x),andThen后执行 f(g(x))

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336

推荐阅读更多精彩内容

  • 前段时间一直在看lambda表达式,但是总感觉吃不透,在深入了解lambda表达式的时候,需要很多基础的知识栈。这...
    西瓜真好吃丶阅读 2,705评论 0 7
  • 简介 概念 Lambda 表达式可以理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主...
    刘涤生阅读 3,191评论 5 18
  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,123评论 9 118
  • 1. 说明 基于前边我们写的58同城数据加载效果、多条目筛选菜单效果,那么我们这节课就来看下花束直播加载效果,可...
    世道无情阅读 277评论 0 0
  • " GPCR/G ProteinNeuronal Signaling- GSK163090????????????...
    莫小枫阅读 230评论 0 0