Java常见问题的简单解法_第1页
Java常见问题的简单解法_第2页
Java常见问题的简单解法_第3页
Java常见问题的简单解法_第4页
Java常见问题的简单解法_第5页
已阅读5页,还剩248页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Java

常见问题的简单解法

目录

章基础知识

lambda表达式

L2

方法引用

L3

构造函数引用

问题

方案

讨论

另见

函数式接口

L5

接口中的默认方法

LC

接口中的静态方法

章java.util,function包

Consumer接口

22

Supplier接口

讨论

另见

2.3Predicate接口

2.4Function接口

问题

方案

讨论

另见

第3章流式操作

3.1流的创建

问题

方案

讨论

另见

3.2装箱流

问题

方案

讨论

另见

3.3利用reduce方法实现归约操作

问题

方案

讨论

另见

3.4利用reduce方法校验排序

问题

方案

讨论

另见

3.5利用peek方法对流进行调试

问题

方案

讨论

3.6字符串与流之间的转换

问题

方案

讨论

另见

7

问题获

方案

讨论

另见

E

问题汇

方案

讨论

另见

9

问题查

方案

讨论

另见

ch

at

eM

n

o

n

ch

at

lM

al

x

ch

at

M

ny

a

使

问10题

方案

讨论

另见

工U

ap

m

ap

tM

a

fl

问题使

方案

讨论

另见

问12题

方案

讨论

另见

问1题3

方案

讨论

另见

第4

1

4.问题

方案

讨论

将流转换为集合

另-

3

将线性集合添加到映射

4问.

4

4问.对映射排序

5

4.问分区与分组

e

4问.下游收集器

7

4.问

查找最大值和最小值

4.问8

创建不可变集合

4.问9

实现Collector接口

章流式操作、lambda表达式与方法引用的相关问题

5.1java.util.Objects类

问题

方案

讨论

5.2lambda表达式与效果等同于final的变量

问题

方案

讨论

另见

5.3随机数流

问题

方案

讨论

另见

5.4Map接口的默认方法

问题

方案

讨论

5.5默认方法用突

问题

方案

讨论

另见

5.6集合与映射的迭代

问题

方案

讨论

另见

5.7利用Supplier创建日志消息

问题

方案

讨论

另见

5.8闭包复合

问题

方案

讨论

另见

5.9利用提取的方法实现异常处理

问题

方案

讨论

另见

5.10受检异常与lambda表达式

5.11泛型异常包装器的应用

问题

方案

讨论

另见

第6章Optional类

6.1Optional的创建

问题

方案

讨论

另见

6.2从Optional中检索值

问题

方案

讨论

另见

6.3getter和setter方法中的Optional

问题

方案

讨论

另见

6.4Optional.flatMap与Optional,map方法

问题

方案

讨论

另见

6.5Optional的映射

问题

方案

讨论

另见

第7章文件I/O

7.1文件处理

问题

方案

讨论

另见

2

7.问题

方案

讨论

另见

3

7.

问题文

方案

讨论

另见

问题文

方案

讨论

另见

第8

e

im

t

a,

v

ja

&

1

I中

P

A

e

im

T

e-

at

问题D

方案

讨论

另见

&2

间题根

方案

讨论

另见

&3

问题调

方案

讨论

&4

e

at

D

al

oc

L

e.

im

t

a.

av

j

e

at

D

l.

ti

u

a.

av

j

问题将

方案

讨论

&

5

问题解

方案

讨论

8.6查找具有非整数小时偏移量的时区

问题

方案

讨论

8.7根据UTC偏移量查找地区名

问题

方案

讨论

8.8获取事件之间的时间

问题

方案

讨论

第9章并行与并发

9.1将顺序流转换为并行流

问题

方案

讨论

9.2并行流的优点

问题

方案

讨论

9.3调整线程池大小

问题

方案

讨论

另见

9.4Future接口

问题

方案

讨论

另见

9.5完成CompletablcFuturc

问题

方案

讨论

另见

9.6多个Co叩leldbleFulure之间的协调(第1部分)

问题

方案

讨论

另见

9.7多个CompletabieFuture之间的协调(第2部分)

问题

方案

讨论

另见

第10章Java9新特性

10.1Jigsaw中的模块

问题

方案

讨论

另见

10.2接口中的私有方法

问题

方案

讨论

10.3创建不可变集合

问题

方案

讨论

另见

10.4新增的Stream方法

问题

方案

讨论

10.5下游收集器:filtering-^flatMapping

问题

方案

讨论

另见

10.6新增的Optional方法

问题

方案

讨论

另见

10.7日期范围

问题

方案

讨论

另见

附录A泛型与Java8

A.1背景

A.2众所周知的事实

A.3容易忽略的事实

A.4通配符与PECS

A.4.1无界通配符

A.4.2上界通配符

A.4.3下界通配符

A.4.4PECS原则

A.4.5多重边界

A.5Java8API示例

A.5.1Stream.max方法

A.5.2Stream.map方法

A.5.3Comparator,comparing方法

A.5.4Map.Entry,coinparingByKey与Map.Entry.comparingByValue方法

A.5.5类型擦除

A.6小结

第1章基础知识

Java8的最大变化是引入了函数式编程(functionalprcgramming)的概念。具体而言,Java8

增加了lambda表达式(lambcaexpression)>方法引用(methodreference)和流(stream)o

如果读者尚未接触过这些新增的函数式特性,或许会惊讶于写出的代码和之前大相径庭。Java8

的变化堪称迄今为止这门语言最大的变化。从许多方面来说,这与学习一门全新的语言并无二致。

读者或许会问,这样做的目的是什么?为什么要对一门已有20年历史且计划保持向后兼容性的

语言做出如此巨大的改变?一门为各方所公认的成熟语言,是否需要这些重大的修改?作为这些

年来最成功的面向对象语言之一,Java为何要转向函数式范式?

答案在于,软件开发领域已经发生变化,希望今后依然立于不败之地的语言同样需要适应这种变

化。20世纪90年代中期,在Java刚问世时,摩尔定律1仍然被奉为金科玉律。人们只需等

上几年,计算机的运行速度就会提高一倍。

1由仙童半导体公司(FairchildSemiconductor)和英特尔联合创始人戈登•摩尔(GordonMoore)提出。根据观察,大约每18

个月,封装到集成电路中的晶体管数量将增加一倍。参见维基百科的“摩尔定律”词条。

如今,硬件不再依赖于通过增加芯片密度来提高速度。相反,连手机都已大部分配备了多核处理

器,这意味着编写的软件需要具备在多处理器环境下运行的能力。函数式编程强调“纯”函数(基

于相同的输入将返回相同的结果,无副作用存在)以及不匕变性,从而简化了并行环境下的编程。

如果不引入任何共享、可变的状态,且程序可以被分解为若干简单函数的集合,就更容易理解并

预测程序的行为。

不过,本书并非一本介绍Haskell.Erlang.Frege或任何其他函数式编程语言的教程,而是侧

重于探讨Java以及它所引入的函数式概念。从本质上讲,Java仍然是一门面向对象的语言。

Java目前支持lambda表达式,它本质上是被视为一类对象(first-classobject)的方法。Java

还增加了方法引用,允许在任何需要lambda表达式的场合使用现有的方法。为利用lambda表

达式和方法引用,Java引入了流模型。流模型生成元素并通过流水线(pipeline)进行传递和过

滤,无须修改原始源代码。

本章的范例将介绍lambda表达式、方法引用与函数式接口(functionalinterface)的基本语

法,并讨论接口中的默认方法和静态方法。有关流的详细讨论,参见第3章。

1.1lambda表达式

问题

用户希望在代码中使用lambda表达式。

方案

使用某种lambda表达式语法,并将结果赋给函数式接口类型的引用。

讨论

函数式接口是一种包含单一抽象方法(singleribstractmethod)的接口。类通过为接口中的所

有方法提供实现来实现任何接口,这可以通过顶级类(top-levelclass)、内部类甚至匿名内部

类完成。

以Runnable接口为例,它从Java1.0开始就已存在。该接口包含的单一抽象方法是run,它

不传入任何参数并返回voidoThread类构造函数传入Runnable作为参数,例1T显示了

Runnable接口的匿名内部类实现。

例ITRunnable接口的匿名内部类实现

publicclass

RurnableDemo{

publicstaticvoid

main(String1]args){

new

Thread(

new

Rurnable(){❶

©Override

publicvoid

rur(){

System,out.print]n(

*insiderunnableusingananonymousinnerclass*);

}

}).start():

)

}

❶匿名内部类

匿名内部类语法以关键字new开头,后面跟着Runnable接口名以及英文小括号,表示定义一个

实现该接口但没有显式名(explicitname)的类。大括号({})中的代码重写run方法,将字

符串打印到控制台。

例1-2中的代码采用lambda表达式,对例1T进行了改写。

例1-2在Thread构造函数中使用lambda表达式

new

Thread(()->System,out.println(

“insideThreadconstructorusinglambda^)),start();

上述代码使用箭头将参数与函数体隔开(由于没有参数,这里只使用一对空括号)。可以看到,

函数体只包含一行代码,所以不需要大括号。这种语法被称为lambda表达式。注意,任何表达

式求值都会自动返回。在本例中,由于printin方法返回的是void,所以该表达式同样会返回

void,与run方法的返回类型相匹配。

lambda表达式必须匹配接口中单一抽象方法签名的参数类型和返回类型,这被称为与方法签名

兼容。因此,lambda表达式属于接口方法的实现,可以将其赋给该接口类型的引用。

例1-3显示了赋给某个变量的lambda表达式。

例1-3将lambda表达式赋给变量

Runrabler=()->System,out.println(

“lambdaexpressionimplementingtherunmethod*);

new

Thread(r).start();

Java库中不存在名为Lambda的类,lambda表达式只能被赋给函数式接口引用。

“将lambda表达式赋给函数式接口”与“lambda表达式属于函数式接口中单一抽象方法的实现”

表示相同的含义。我们可以将lambda表达式视为实现接口的匿名内部类的主体。这就是lambda

表达式必须与抽象方法兼容的原因,其参数类型和返回类型必须匹配该方法的签名。注意,所实

现方法的名称并不重要,它不会作为lambda表达式语法的一部分出现在代码中。

因为run方法不传入参数,并且返回void,所以本例特别简单。函数式接口

java.io.Fi1enameFi1ter从Java1.0开始就是Java标准库的一部分,该接口的实例被用作

File,list方法的参数,只有满足该方法的文件才会被返回。

根据Javadoc的描述,FilenameFilter接口包含单一抽象方法accept,它的签名如下:

boolean

accept(Filedir,Stringname)

其中,File参数用于指定文件所在的目录,String用于指定文件名。

例1-4采用匿名内部类来实现FilenameFilter接口,只返回Java源文件。

例1一4FilenameFilter的匿名内部类实现

Filedirectory=

new

File(*./src/main/java*):

Stringt]names=directory.list(

new

FilenameFilter。{O

©Override

publicboolean

accept(Filedir,Stringname){

return

name.cndsWithC.java");

});

System,out.printin(Arrays.asList(nanes));

❶匿名内部类

在例1-4中,如果文件名以.java结尾,accept方法将返回Irue,否则返回false。

而例1-5采用lambda表达式实现FilenameFilter接口。

例1-5FilenameFilter接口的lambda表达式实现

Filedirectory=

new

File(*./src/main/java*):

StringE]names=directory,list((dir,name)->name.endsWith(*.java*));❶

System,out.printIn(Arrays.asList(names));

❶lambda表达式

可以看到,代码要简单得多。参数包含在小括号中,但并未声明类型。在编译时,编译器发现list

方法传入一个FilenameFilter类型的参数,从而获知其单一抽象方法accept的签名,进而了

解accept的参数为File和String,因此兼容的lambda表达式参数必须匹配这些类型。由于

accept方法的返回类型是布尔值,所以箭头右侧的表达式也必须返回布尔值。

如例卜6所示,我们也可以在代码中指定数据类型。

例卜6具有显式数据类型的lambda表达式

Filedirectory=

new

File("./src/main/java*):

Stringt]names=directory,list((Filedir,Stringname)->O

name.endsWilh(".java"));

❶显式数据类型

此外,如果lambda表达式的实现多于一行,则需要使用大括号和显式返回语句,如例1-7所示。

例1-71ambda代码块

Filedirectory=

new

Eile(*./src/main/java*);

String[]names=directory.list((Filedir,Stringname)->(O

return

name.endsWith(*.java");

});

System.out.printIn(Arrays.asList(nanes));

❶代码块语法

这就是1ambda代码块(blocklambda)o在本例中,虽然代码主体只有一行,但可以使用大括

号将多个语句括起来。注意,不能省略return关键字。

lambda表达式在任何情况下都不能脱离上下文存在,上下文指定了将表达式赋给哪个函数式接

口。lambda表达式既可以是方法的参数,也可以是方法的返回类型,还可以被赋给引用。无论哪

种情况,赋值类型必须为函数式接口。

1.2方法引用

问题

用户希望使用方法引用来访问某个现有的方法,并将其作为lambda表达式进行处理.

方案

使用双冒号表示法(::)将实例引用或类名与方法分开。

讨论

如果说lambda表达式本质上是将方法作为对象进行处理,那么方法引用就是将现有方法作为

laFTbda表达式进行处理。

例如,java.lang.Iterable接口的forEach方法传入Consumer作为参数。如例1~8所示,

Consumer可以作为lambda表达式或方法引用来实现。

例1-8利用方法引用访问printin方法

Stream,of(3,1,4,1,5,9)

.forEach(x->System,out.println(x));❶

Stream,of(3,1,4,1,5,9)

.forEach(System,out::println);❷

Consumcr<lntcgcr>printer=System,out::printIn;❸

Stream,of(3,1,4,1,5,9)

.forEach(printer);

❶使用lambda表达式

❷使用方法引用

❸将方法引用赋给函数式接口

双冒号表示法在System,out实例上提供了对printin方法的引用,它属于PrintStream类型

的引用。方法引用的末尾无须括号。在本例中,程序将流的所有元素打印到标准输出。2

2讨论lambda表达式或方法引用时,很难不涉及流,第3章将专门讨论流。口前可以这样理解:流依次产生一系列元素,但不

会将它们存储在任何位置,也不会对原始源进行修改。

S如果编写一个只有一行的lambda表达式来调用方法,不妨考虑改用等价的方法引用。

与lambda语法相比,方法引用具有几个(不那么显著的)优点。首先,方法引用往往更短。其

次,方法引用通常包括含有该方法的类的名称。这两点使得代码更易于阅读。

如例1-9所示,方法引用也可以和静态方法一起使用。

例-9在静态方法中使用方法引用

Stream,generate(Math::random)❶

.limit(lO)

.forEach(System,out::println);❷

❶静态方法

❷实例方法

Stream接口定义的generate方法传入Supplier作为参数。Supplier是一个函数式接口,其

单一抽象方法get不传入任何参数且只生成一个结果。Math类的random方法与get方法的签

名相互兼容,因为random方法同样不传入任何参数,且产生一个0到1之间、均匀分布的双

精度伪随机数,方法引用Math::random表示该方法是Supplier接口的实现。

由于Stream,generate方法产生的是一个无限流(infinitestream),我们通过limit方法限

定只生成10个值,然后使用方法引用System,out::println将这些值打印到标准输出,作为

Consumer的实现。

语法

方法引用包括以下三种形式,其中一种存在一定的误导性。

object::instanceMethod

引用特定对象的实例方法,如System,out::printlno

Class::staticMethod

引用静态方法,如Math::max«

Class::instanceMethod

调用特定类型的任意对象的实例方法,如String::lengtho

最后一种形式或许

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论