Java8之Stream

本文详细探讨了Java8的新特性,包括Stream API的使用,Lambda表达式的概念与应用,以及函数式接口的重要性和实践。通过实例解析了行为参数化、流处理、函数式编程的基本思想,同时介绍了如何利用Java8的默认方法和方法引用简化代码。此外,还讨论了Collector在流操作中的作用以及如何自定义函数式接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么关心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

对于下面的函数描述符,你会使用哪种函数式接口

  1. T -> R
  2. (int,int) -> int
  3. T -> void
  4. () -> T
  5. (T,U) -> R
  6. (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

函数式接口

函数式接口好处(TODO)

自定义函数式接口

jdk中的函数式接口

lambda表达式

lambda表达式好处(TODO)

匿名内部类转lambda表达式

Lambda 语法简化

StreamAPI

streamAPI好处(TODO)

Stream的生成方式

stream的操作类型Intermediate

stream的操作类型Terminal

Collector

collector干嘛用的

collector中的5个抽象方法

supplier
accumulator
combiner
finisher
characteristics

Collectors

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值