java in action_Java8 in action

解决的问题:

behavior parameterization,即可以把一段code,逻辑作为参数传入;

这样做的目的,当然为了代码抽象和重用,把变化的逻辑抽象出去;

在java中,如果要实现behavior parameterization,需要通过传入类对象的方式,你首先要声明很多类,verbose

就算你用匿名类的方式,也会大大影响代码的可读性

所以lambda,是function programing的元素,可以将一个匿名函数作为参数传入

Lambdas

A lambda expression can be understood as a concise representation of an anonymous function that can be passed around

 Anonymous— We say anonymous because it doesn’t have an explicit name like a method would normally have: less to write and think about!

 Function— We say function because a lambda isn’t associated with a particular class like a method is. But like a method, a lambda has a list of parameters, a body, a return type, and a possible list of exceptions that can be thrown.

 Passed around— A lambda expression can be passed as argument to a method or stored in a variable.

 Concise— You don’t need to write a lot of boilerplate like you do for anonymous classes.

cdcba0b9401602a3067049f02d17554d.png

在什么地方可以使用lamda?

So where exactly can you use lambdas? You can use a lambda expression in the context of a functional interface.

In a nutshell, a functional interface is an interface that specifiesexactly one abstract method.

3fd06d52faa8a03a292499ca7700e2e3.png

可以看到lambda在用法上和匿名类是等价的

Function descriptor

在java8中,有多少种functional interface,

其中function description表示functional的signature,比如Consumer,参数T,无返回值

14c4f463bb259d333125396e2867bd51.png

Predicate,典型的filter场景

The java.util.function.Predicate interface defines an abstract method named test that accepts an object of generic type T and returns a boolean.

Predicate nonEmptyStringPredicate = (String s) -> !s.isEmpty();

List nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

Consumer,消费者场景

The java.util.function.Consumer interface defines an abstract method named accept that takes an object of generic type T and returns no result (void).

8de48d15209bd40a4c8e357aac162e04.png

Function,transform场景

The java.util.function.Function interface defines an abstract method named apply that takes an object of generic type T as input and returns an object of generic type R.

fd7801b560352f07c35219235dfd0301.png

Type inference

用于编译器会做类型check和推导,所以你可以省略参数类型

1b33b187ebd27ac28c2172d59295301b.png

Using local variables,弱版闭包

int portNumber = 1337;

Runnable r= () -> System.out.println(portNumber)

看到lambda,使用临时变量

They’re called capturing lambdas

和闭包的不同是,他有限制,

Lambdas are allowed to capture (that is, to reference in their bodies) instance variables and static variables without restrictions.

But local variables have to be explicitly declared final or are effectively final.

In other words, lambda expressions can capture local variables that are assigned to them only once.

34a205b2b76d3a03c18d96e696d70917.png

这样会报错,因为你多次修改

我的理解,其实你改不改,对于Java的实现是没有问题,反正都是在你引用的时候,产生一份copy

但是如果你修改了值,容易产生歧义,你会期望引用的值变成你改的值,其实不会

Method references

Method references let you reuse existing method definitions and pass them just like lambdas.

In some cases they appear more readable and feel more natural than using lambda expressions.

b3c378f0f1408cd46d6720cbf5bcaea4.png

You can think of method references as syntactic sugar for lambdas that refer only to a single method because you write less to express the same thing.

一种用于更简单的表示lambda的语法糖

Recipe for constructing method references

There are three main kinds of method references:

1. A method reference to a static method (for example, the method parseInt of Integer, written Integer::parseInt)

2. A method reference to an instance method of an arbitrary type (for example, the method length of a String, written String::length)

3. A method reference to an instance method of an existing object (for example, suppose you have a local variable expensiveTransaction that holds an object of type Transaction, which supports an instance method getValue; you can write expensiveTransaction::getValue)

9750bdaabc57d1c0e400f3fb2a30e009.png

Constructor references

You can create a reference to an existing constructor using its name and the keyword new as follows: ClassName::new. It works similarly to a reference to a static method.

9d79807faf37049075be2f59d85e5130.png

注意,Apple::new,不是调用new,这个是产生一个function interface,supplier

对于带参数的构造函数,生成的就是function

23058db704966fd440183cecb8c8f40c.png

Useful methods to compose lambda expressions

Composing Comparators

8fb879544662c3d4db58042544eed613.png

Composing Predicates

fadb1836599c1e5ceb41a41d8ac1d99e.png

ffd98370ffe3788f5af446e52f228135.png

Composing Functions

e0a74e1b5ea1a002e28f7faa93da178f.png

55737af4f496098b740d7cf3e4ae9d57.png

Streams API

To summarize, the Streams API in Java 8 lets you write code that’s

 Declarative— More concise and readable

 Composable— Greater flexibility

 Parallelizable— Better performance

说白,就是以function programming的方式去处理collection,不需要显式的去写迭代,所以declarative

并且,可以透明的处理并行化问题

531cd3d5774536322cc7a5c02365c628.png

Streams vs. collections

72115acc29f6842b530099326d7b3ea8.png

Working with streams

To summarize, working with streams in general involves three items:

 A data source (such as a collection) to perform a query on

 A chain of intermediate operations that form a stream pipeline

 A terminal operation that executes the stream pipeline and produces a result

Intermediate operations such as filter or sorted return another stream as the return type.

This allows the operations to be connected to form a query. What’s important is that intermediate operations don’t perform any processing until a terminal operation is invoked on the stream pipeline—they’re lazy.

752a8ada088710b9a4c3acb194ba1402.png848a5ea233178c2e6d133b5e034024de.png

Numeric streams

Mapping to a numeric stream

The most common methods you’ll use to convert a stream to a specialized version are mapToInt, mapToDouble, and mapToLong.

d439fe61a04ccf11908a21c2b9d61660.png

这样可以直接用sum

和下面的写法比较一下,

c0489ca3662384c56351d21ee07b8c47.png

Converting back to a stream of objects

c1ef00eae58ff583abc7a999086c7bb8.png

Numeric ranges

46e3c3064cb7a2d765ccb9fb3e6cd427.png

Building streams

Streams from values

Stream stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");

Stream emptyStream = Stream.empty();

Streams from arrays

da0ee8157ec36166f250d4fdd7d26c35.png

Streams from files

86d912131deaf7946e522ea08a158d2f.png

Streams from functions: creating infinite streams

9d790fb0080ac3664e7e23064c4fb7ba.pngb0be8362abd1c36fd9c1cdc9087bdecd.png

Collecting data with streams

Collectors as advanced reductions

List transactions = transactionStream.collect(Collectors.toList());

f57d6cd1a4b19d5e2b0c81d46120db50.png6430bb172b9a15c225512b596bee6db8.png47dac383a3f76576874423516c51de4d.png

Parallel data processing and performance

通过parallel来打开并行

43ef8bae7cc6f760596bbc8afa153ca4.png

sequential(),可以切换到串行

这里的并行是由fork/join来实现的

fork/join framework

The fork/join framework was designed to recursively split a parallelizable task into smaller tasks and then combine the results of each subtask to produce the overall result.

可以理解成local的map reduce

It’s an implementation of the ExecutorService interface, which distributes those subtasks to worker threads in a thread pool, called ForkJoinPool.

在java7中,我要这样写fork/join应用,比如一个简单的并行求和

1eaec2cf4fe22599158e1502c2bb2966.png

注意在compute中,我们会判断阈值,如果不满足,就不断的二分,并递归的调用

然后,这样调用

public static long forkJoinSum(longn) {long[] numbers = LongStream.rangeClosed(1, n).toArray();

ForkJoinTask task = newForkJoinSumCalculator(numbers);return newForkJoinPool().invoke(task);

}

f6050c96905939a833d972b2344c0393.png

Spliterator

这是对fork逻辑的抽象

Java 8 already provides a default Spliterator implementation for all the data structures included in its Collections Framework.

Collections now implements the interface Spliterator, which provides a method spliterator.

在Java8中,所有Collections都是实现Spliterator接口

public interface Spliterator{boolean tryAdvance(Consumer super T>action);

SpliteratortrySplit();longestimateSize();intcharacteristics();

}

The algorithm that splits a Stream into multiple parts is a recursive process and proceeds as shown in figure 7.6.

9800ec02df4f17096b56e9e961243069.png

split的过程就是不断的调用trySplit

实现WordCount功能的Spliterator

64a6ee4af2c255197462d71d86fbc460.png9b2036af1fbd923caee6c07ee340d974.png

Default methods

Interface如果发生改变,增加function,那么所有实现该interface的类都需要修改以实现新的function,这个太烦躁了;

所以在Java8,给interface加了default methods

96fc3089a01dad9a231eda1bc1d6b826.png

Using Optional as a better alternative to null

大家是不是都被NullPointerException烦的不行

需要写出这样丑陋的代码

aaf9c06e3ffc29e3b2b15321203ce731.png6605c9bf3b4de73613afb8f5f9eb0985.png

Java 8 introduces a new class called java.util.Optional that’s inspired by the ideas of Haskell and Scala.

Object value = map.get("key");

写成,

Optional

也可以写成这样,

43d888666f772a835f95f3c98443ae2d.png

区别就是of会抛异常

option支持的操作

0a4ac4406a5fae089ab87ed66115c5eb.png

开始的例子,可以写成,

ebe5fff03f2b9d91329e94c959da8ddc.png

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页

打赏

曹德一

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者