为什么关心Java8
Java8与并发编程
答:
Java8之前,必须利用多线程才能使用多个内核,问题是线程用起来很难,也容易出错,
Java8提供了一个新的API,Stream支持多处理器的并行操作
在多个处理器内核之间使用synchronize,其代价往往比预期要大得多
行为参数化是什么
答:
:
:
:
例如:匿名内部类,但是还不够简洁,请看Java8,函数式编程,lambda表达式
“流处理”你能想到什么
答:
:
:
:
Java的流处理,一个程序的输入可能是另一个程序的输出(System.in和System.out)
linux的流处理:cat file1 file2 | sort | tail -3
函数式编程的基石,两点
答:
:
:
:
1.没有共享的可变数据
2.将方法和函数传递给其他方法的能力
方法作为参数传递进去举一个例子
答:
:
:
筛选红苹果和绿苹果。P12
Function<Apple,Boolean>与Predicate的区别
答:
:
:
函数与谓词
思考
题:
filterApples(apples,Apple::isGreen)
上面这个可以筛选出绿苹果
问题是:isGreen这种只能用一两次的短方法写一堆定义有点烦,还有其他解决方式吗?
答:
:
:
:
filterApples(apples,(Apple a) -> "green".equals(a.getColor()));
默认方法的好处
答:
:
:
:
Java8之前,接口若要扩充一个方法,那么其子类都要实现这个方法,现在不需要了,提供一个default方法即可
方法匿名与有方法名比,好处是什么
答:
:
:
:
普通方法的坏处,写的少,想得多
什么是函数式接口
答:
:
:
:
只定义一个抽象方法的接口
思考
问题:
B是函数式接口吗?
interface A {
void f();
}
interface B extends A{
void f();
}
答:
:
:
:
:不是,有两个add方法
看下面的函数描述符代表什么意思
() -> void
(Apple) -> int
对于下面的函数描述符,你会使用哪种函数式接口
- T -> R
- (int,int) -> int
- T -> void
- () -> T
- (T,U) -> R
- (T,T) -> T
答:
:
:
:
7. Function<T,R>
8. IntBinaryOperator
9. Consumer<T>
10.Supplier<T>
BiFunction<T,U,R>
BinaryOperator<T>
Predicate与IntPredicate的区别
答:
:
:
:
IntPredicate不需要自动装箱与拆箱,节省性能
lambda表达式找对应函数式接口
1.布尔表达式(List list) -> list.isEmpty()
2.创建对象 () -> new Apple()
3.消费一个对象 (Apple a) -> sout(a.getWeight())
4.从一个对象中选择或者提取 (String s) -> s.length()
5.合并两个值 (int a,int b) -> a*b
6.比较两个对象 (Apple a1,Apple a2) -> a1.getWeight . CompareTo(a2.getWeight)
答:
:
:
:
:
:
Predicate<List<String>>
Supplier<Apple>
Consumer<Apple>
Function<String,Integer>或ToIntFunction<String>
IntBinaryOperator
Comparator<Apple>或BiFunction<Apple,Apple,Integer>
什么是void兼容
答:
:
:
:
Predicate<Apple> p = (Apple a) -> list.add(a)
和
Consumer<Apple> c = (Apple a) -> list.add(a)
语法都不会报错,因为Consumer的返回是void
Objective o = () -> {sout(xxx)}为什么不能通过编译
答:
:
:
:目标类型object不是一个函数式接口
为什么lambda表达式使用局部变量必须final修饰,而实例变量不需要
答:
:
:
:
:
实例变量都存储在堆中,局部变量保存在栈上。如果lambda可以直接访问局部变量,且lambda是在一个线程中使用,可能会在分配该变量的线程将这个变量回收之后,去访问该变量。因此Java在访问自由局部变量时,实际上是在访问它的副本,而不是在访问原始变量,如果局部变量是final仅赋值一次那就没什么了
如何理解闭包、匿名类、lambda表达式
答:
:
:
:
:
1.闭包是一个函数的实例,可以无限制地访问那个函数的非本地变量。
2.闭包可以作为参数传递给另外一个函数,它也可以访问和修改其作用域之外的变量,类似于Java的lambda和匿名类
3.但有一个限制,不能修改局部变量的内容,变量必须隐式最终,可以认为lambda是对值封闭,而不是对变量封闭。
4.这种限制存在的原因在于局部变量保存在栈上,并且隐式表示他们限于其所在线程
Java8实战P52
思考
省略了哪些?
inventory.sort(comparing(Apple::getWeight))
1.Comparator.comparing(Function<Apple,Integer>)
lambda方法引用的基本思想
如果一个lambda代表的只是直接调用这个方法,那最好还是用名称来调用它,而不是描述如何调用它
写出下面的lambda表达式的方法引用
(Apple a) -> a.getWeight()
() -> Thread.currentThread().dumpStack()
(str, i) -> str.substring(i)
(String s) -> sout(s)
答:
:
:
Apple::getWeight
Thread.currentThread::dumpStack
String::substring
System.out::println
三类方法引用
(args) -> ClassName.staticMethod(args)
(agr0,rest) -> arg0.instanceMethod(rest)
(args) -> expr.instanceMethod(args)
答:
:
:
ClassName::staticMethod
ClassName::instanceMethod
expr::instanceMethod
list.sort((s1,s2) -> s1.compareToIgnoreCase(s2))可以简化成方法引用吗
String::compareToIgnoreCase,相当于第二类
思考
Supplier<Apple> c1 = Apple::new
对应无参Apple()
若Apple(Integer weight) 的Apple::new还能对应Supplier吗?
答:
:
:
:
不能,应该对应Function<Integer,Apple>
比较器复合、谓词复合、函数复合
Java8实战P60
流与集合的区别
1.当用户想看一部电影时,可以买DVD看,也可以在线观看,DVD是将整个电影下载下来了,而在线只是下载用户看到的和缓存的一小部分
2.流的数据处理类似于数据库,如filter、map、reduce,而集合没有
3.流是内部迭代,集合是外部迭代
将[“hello”,“world”],去重返回[H,e,l,W,o,r,d]
错误示范:
stream.map(word -> word.split(""))
.distinct()
.collect(toList())
正确做法:
思路:
Stream words
Stream words.flatMap(???).distinct()
???里应该是hello切割成数组String[],再转Stream,类推world
flatMap再将两个stream合为一个Stream
stream.flatMap(word -> Arrays.stream(word.split("")))
.distinct().collect(Collectors.toList());
stream.map(w -> w.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
上面两个居然都行,思路一样的
给定[1,2,3]和[3,4],返回[{1,3},{1,4},{2,3},{2,4},{3,3},{3,4}]
int[] num1
int[] num2
num1.stream().flatMap(i -> {
num2.stream().map(
j -> new int[]{i,j}
)
})...略
检查是否至少匹配一个元素
boolean = stream.anyMatch(apple -> {
"red".equals(apple.getColor())
})
检查是否匹配所有元素
allMatch