Skip to content

Commit 1bfb093

Browse files
author
jackchan1999
committed
updates
1 parent 50162c9 commit 1bfb093

File tree

7 files changed

+127
-11
lines changed

7 files changed

+127
-11
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
* [继承](https://alleniverson.gitbooks.io/java-basic-introduction/content/第3章%20面向对象/继承.html)
5555
* [多态](https://alleniverson.gitbooks.io/java-basic-introduction/content/第3章%20面向对象/多态.html)
5656
* [抽象类与接口](https://alleniverson.gitbooks.io/java-basic-introduction/content/第3章%20面向对象/抽象类与接口.html)
57-
* [接口回调](第3章 面向对象/接口回调.md)
57+
* [接口回调](https://alleniverson.gitbooks.io/java-basic-introduction/content/第3章%20面向对象/接口回调.html)
58+
* [闭包](https://alleniverson.gitbooks.io/java-basic-introduction/content/第3章%20面向对象/闭包.html)
5859
* [内部类](https://alleniverson.gitbooks.io/java-basic-introduction/content/第3章%20面向对象/内部类.html)
5960
* [异常](https://alleniverson.gitbooks.io/java-basic-introduction/content/第3章%20面向对象/异常.html)
6061
* [第4章 常见对象](https://alleniverson.gitbooks.io/java-basic-introduction/content/第4章%20常见对象/README.html)

SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
* [多态](第3章 面向对象/多态.md)
3737
* [抽象类与接口](第3章 面向对象/抽象类与接口.md)
3838
* [接口回调](第3章 面向对象/接口回调.md)
39+
* [闭包](第3章 面向对象/闭包.md)
3940
* [内部类](第3章 面向对象/内部类.md)
4041
* [异常](第3章 面向对象/异常.md)
4142

第11章 新特性/Lambda表达式.md

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
11
## Lambda表达式
22

3-
将代码块作为函数参数,函数式接口,相对于一个匿名方法,主要作用是代替匿名内部类的烦琐语法。
3+
Lambda表达式本质上是一种匿名方法,将代码块作为函数参数,函数式接口,相当于一个匿名方法,主要作用是代替匿名内部类的烦琐语法。
44

55
Lambda表达式有三部分组成
66

7-
- 参数列表
7+
- 形参列表。可以自动类型推导,可以省略参数类型。只有一个参数,可以省略形参列表的()
88
- 箭头(->)
9-
- 代码块
9+
- 代码块{},代码块只有一条语句,可以省略{};代码块只有一条return语句,可以省略return关键字。
10+
11+
只有一个抽象方法的接口(函数式接口),都可以使用Lambda表达式的写法。
12+
13+
```java
14+
public interface MyListener{
15+
String doSomething(String a, int b);
16+
}
17+
MyListener listener = (String a, int b)->{
18+
String ret = a + b;
19+
return ret;
20+
}
21+
// 自动类型推断
22+
MyListener listener = (a, b)->{
23+
String ret = a + b;
24+
return ret;
25+
}
26+
```
1027

1128
## 函数式接口
1229

13-
只包含一个抽象方法的接口,可以包含多个默认方法,类方法
30+
函数式接口代表只包含一个抽象方法的接口,函数式接口可以包含多个默认方法,类方法,但只能声明一个抽象方法。
1431

1532
Lambda表达式的结果就是被当成对象。
1633

第3章 面向对象/抽象类与接口.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,8 @@ class ClassName implements Interface1,Interface2,[....]{
428428

429429
2.设计层面上的区别
430430

431+
接口是事物的能力,直接理解就是约定;抽象类是事物的本质。
432+
431433
抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 “是不是”的关系,而 接口 实现则是 “有没有”的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。
432434

433435
设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简单例子,大家都用过ppt里面的模板,如果用模板A设计了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对ppt B和ppt C进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。

第3章 面向对象/接口回调.md

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
所谓回调,在实现具有通用性质的应用框架时非常常见:
1+
## 回调机制
2+
3+
所谓回调,在实现具有通用性质的应用框架时非常常见:对于一个具有通用性质的程序框架来说,程序架构完成整个应用的通用功能、流程,但在某个特定的点上,需要一段业务相关的代码——通用程序架构无法完成这段代码,那么程序架构会在这个点上留一个“空”。
4+
5+
对于Java程序来说,程序架构在某个点上留的”空“,有2种实现方式
6+
7+
- 以接口形式存在
8+
- 以抽象方法的形式存在
9+
10+
回调机制的第一种实现方式就是典型的命令者模式。
211

312
## 接口回调
413

@@ -304,4 +313,56 @@ public class Test {
304313

305314
- 回调、轮询
306315

307-
很明显,使用异步来编写程序性能会远远高于同步,但是异步的缺点是编程模型复杂。想想看,你得知道什么时候通知你“汉堡做好了”,而通知你的方法也各不相同。如果是服务员跑过来找到你,这是回调模式,如果服务员发短信通知你,你就得不停地检查手机,这是轮询模式。总之,异步的复杂度远远高于同步
316+
很明显,使用异步来编写程序性能会远远高于同步,但是异步的缺点是编程模型复杂。想想看,你得知道什么时候通知你“汉堡做好了”,而通知你的方法也各不相同。如果是服务员跑过来找到你,这是回调模式,如果服务员发短信通知你,你就得不停地检查手机,这是轮询模式。总之,异步的复杂度远远高于同步
317+
318+
## 回调函数
319+
320+
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。
321+
322+
回调函数是你写一个函数,让预先写好的系统来调用。你去调用系统的函数,是直调。让系统调用你的函数,就是回调。但假如满足于这种一句话结论,是不会真正明白的。
323+
324+
回调函数可以看成,让别人做事,传进去的额外信息。
325+
326+
比如 A 让 B 做事,根据粒度不同,可以理解成 A 函数调用 B 函数,或者 A 类使用 B 类,或者 A 组件使用 B 组件等等。反正就是 A 叫 B 做事。
327+
328+
当 B 做这件事情的时候,自身的需要的信息不够,而 A 又有。就需要 A 从外面传进来,或者 B 做着做着再向外面申请。对于 B 来说,一种被动得到信息,一种是主动去得到信息,有人给这两种方式术语,叫信息的 push,和信息的 pull。
329+
330+
A 调用 B,A 需要向 B 传参数。如简单的函数:
331+
332+
```c
333+
int max(int a, int b);
334+
```
335+
336+
要使用这函数,得到两者最大的值, 外面就要传进来 a, b。这个很好理解。
337+
338+
```c
339+
void qsort(void *, size_t, size_t, int (*)(const void *, const void *));
340+
```
341+
342+
而这个函数用于排序,最后一个参数就是回调函数,似乎就比较难以理解了。这是因为人为割裂了代码和数据。
343+
344+
我们暂停一下,看看计算机中比较诡异的地方,也就是代码(code)和数据(data)的统一。这是一个槛,如果不跨过这槛,很多概念就不清楚。我们常常说计算机程序分成 code 和 data 两部分。很多人会理解成,code 是会运行的,是动态的,data 是给 code 使用,是静态的,这是两种完全不同的东西。
345+
346+
其实 code 只是对行为的一种描述,比如有个机器人可以开灯,关灯,扫地。如果跟机器人约定好,0 表示开灯,1 表示关灯,2 表示扫地。我发出指令串,0 1 2,就可以控制机器人开灯,关灯,扫地。再约定用二进制表示,两位一个指令,就有一个数字串,000111,这个时候 000111 这串数字就描述了机器人的一系列动作,这个就是从一方面理解是 code,它可以控制机器人的行为。但另一方面,它可以传递,可以记录,可以修改,也就是数据。只要大家都协商好,code 就可以编码成 data, 将 data 解释运行的时候,也变成了 code。
347+
348+
code 和 data 可以不用区分,统一称为信息。既然 int max(int a, int b) 中 int,double 等表示普通 data 的东西可以传递进去,自然表示 code 的函数也可以传进去了。有些语言确实是不区分的,它的 function(表示code)跟 int, double 的地位是一样的。这种语言就为函数是第一类值。
349+
350+
而有些语言是不能存储函数,不能动态创建函数,不能动态销毁函数。只能存储一个指向函数的指针,这种语言称为函数是第二类值。
351+
352+
另外有些语言不单可以传递函数,函数里面又用到一些外部信息(包括code, data)。那些语言可以将函数跟函数所用到的信息一起传递存储。这种将函数和它所用的信息作为一个整体,就为闭包。
353+
354+
过了这个槛,将代码和数据统一起来,很多难以理解的概念就会清晰很多。
355+
356+
现在我们再回头看看回调函数。回调函数也就是是 A 让 B 做事,B 做着做着,信息不够,不知道怎么做了,就再让外面处理。
357+
358+
比如上述排序例子,A 让 B 排序,B 会做排序,但排序需要知道哪个比哪个大,这点 B 自己不知道,就需要 A 告诉它。而这种判断大小本身是一种动作,既然 C 语言中不可以传进第一值的函数,就设计成传递第二值的函数指针,这个函数指针就是 A 传向 B 的信息,用来表示一个行为。这里本来 A 调用 B 的,结果 B 又调用了 A 告诉它的信息,也就叫 callback。
359+
360+
再比如 A 让 B 监听系统的某个消息,比如敲了哪个键。跟着 B 监听到了,但它不知道怎么去处理这个消息,就给外面关心这个消息,又知道怎么去处理这个消息的人去处理,这个处理过程本身是个行为,既然这个语言不可以传递函数,又只能传一个函数指针了。假如我将函数指针存储下来,以后就可以随时调用。代码和数据都是信息,数据可以存储下来,用来表示行为的函数自然也可以存储下来。
361+
362+
跟着有些人有会引申成,什么注册啊,通知啊等等等。假如 B 做监听,C, D, E, F, G, H 告诉 B 自己有兴趣知道这消息,那 B 监听到了就去告诉 C,D,E,F,G等人了,这样通知多人了,就叫广播。
363+
364+
理解后进行思考,根本不用关心术语。术语只是为了沟通,别人要告诉你,或者你去告诉人,使用的一套约定的词语。同一个东西往往有不同术语。
365+
366+
再将回调的概念泛化,比如某人同时关心 A, B, C, D, E, F 事件,并且这些事件是一组的,比如敲键盘,鼠标移动,鼠标点击等一组。将一组事件结合起来。在有些语言就映射成接口,接口有 N 个函数。有些语言就映射成一个结构,里面放着 N 个函数指针。跟着就不是将单个函数指针传进去,而是将接口,或者函数指针的结构传进去。根据不同的用途,有些人叫它为代理,监听者,观察者等等。
367+
368+
实际上也是将某种行为存储下来,以后有需要再进行调用。跟回调函数在更深层次是没有区别的。

第3章 面向对象/闭包.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
## 函数编程之闭包漫谈(Closure)
2+
3+
### 函数是什么
4+
5+
```python
6+
>>> def ExFunc(n):
7+
sum=n
8+
def InsFunc():
9+
return sum+1
10+
return InsFunc
11+
12+
>>> myFunc=ExFunc(10)
13+
>>> myFunc()
14+
>>> myAnotherFunc=ExFunc(20)
15+
>>> myAnotherFunc()
16+
>>> myFunc()
17+
>>> myAnotherFunc()
18+
>>>
19+
```
20+
21+
在这段程序中,函数InsFunc是函数ExFunc的内嵌函数,并且是ExFunc函数的返回值。我们注意到一个问题:内嵌函数InsFunc中引用到外层函数中的局部变量sum,IronPython会这么处理这个问题呢?先让我们来看看这段代码的运行结果。当我们调用分别由不同的参数调用ExFunc函数得到的函数时(myFunc(),myAnotherFunc()),得到的结果是隔离的,也就是说每次调用ExFunc函数后都将生成并保存一个新的局部变量sum。其实这里ExFunc函数返回的就是闭包。
22+
23+
『纯』的函数是没有状态的,加入了闭包以后就变成有状态的了,相对于一个有成员变量的类实例来说,闭包中的状态值不是自己管理,可以认为是『上帝』在管理。
24+
25+
- 动态作用域,词法作用域
26+
- 把数据和作用域绑定到一起就是闭包。
27+
- 将一个上下文的私有变量的生命周期延长的机制。
28+
- 调用了**局部变量****函数**就是闭包!
29+
30+
### 引用环境
31+
32+
按照命令式语言的规则,ExFunc函数只是返回了内嵌函数InsFunc的地址,在执行InsFunc函数时将会由于在其作用域内找不到sum变量而出错。而在函数式语言中,当内嵌函数体内引用到体外的变量时,将会把定义时涉及到的引用环境和函数体打包成一个整体(闭包)返回。现在给出引用环境的定义就容易理解了:引用环境是指在程序执行中的某个点所有处于活跃状态的约束(一个变量的名字和其所代表的对象之间的联系)所组成的集合。闭包的使用和正常的函数调用没有区别。
33+
34+
由于闭包把函数和运行时的引用环境打包成为一个新的整体,所以就解决了函数编程中的嵌套所引发的问题。如上述代码段中,当每次调用ExFunc函数时都将返回一个新的闭包实例,这些实例之间是隔离的,分别包含调用时不同的引用环境现场。不同于函数,闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

第6章 集合框架/Predicate和Stream操作集合.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
## Predicate 操作集合
22

3-
Predicate 谓词对象,函数式接口
3+
Predicate 谓词对象,函数式接口,可以使用Lambda表达式作为参数。
44

55
- test()
66

77
Collection的removeIf(Predicate filter)方法,批量删除符合filter条件的元素
88

9-
## Stream操作集合
9+
## Stream 操作集合
1010

1111
流式 API,获取Stream:Collection的stream()方法
1212

@@ -29,9 +29,9 @@ Collection的removeIf(Predicate filter)方法,批量删除符合filter条件
2929
| 方法声明 | 功能描述 |
3030
| -------------- | ----- |
3131
| filter() | 过滤 |
32-
| map() | |
32+
| map() | 转换 |
3333
| mapToXxx() | 一对一转换 |
34-
| flatMap() | |
34+
| flatMap() | 集合扁平化 |
3535
| flatMapToXxx() | |
3636
| peek() | |
3737
| skip() | |

0 commit comments

Comments
 (0)