1、简单的lamda表达式
如果一个接口中有多个方法,lamda不支持
interface A {
void testA();
}
interface B {
void testB(int x);
}
public class Test{
public static void main(String[] args) {
//不带参数的lamda表达式
A a = ()->{ /*TODO*/ };
//只有一条语句的lamda表达式
B b = x -> System.out.println(x);
//带参数的lamda表达式
B b1 = (int x) -> { /*TODO*/ };
}
}
2、流
public class Test{
static ArrayList<Integer> list = new ArrayList<>();
public static void main(String[] args) {
for (int i = 0; i < 30; i++) {
list.add(i);
}
//迭代器遍历
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()) {
Integer data = iterator.next();
if(data == 10) {
System.out.println("find data==>"+10);
}
}
//使用流进行遍历
long count = list.stream().filter(data -> {
if(data==10) {
System.out.println("find data==>" + 10);
return true;
}
return false;
}).count();
System.out.println("count==>"+count);
}
}
以上都是遍历集合,查找并打印。
第一种使用迭代器操作
第二种使用流操作
filter为过滤方法,只是描述stream,但是不会做什么实质的工作。这种方法叫做懒性求值方法。
count会从stream产生值,叫做及早求值方法
2.1 一些常用的流操作
2.1.1
List<String> list = Stream.of("a", "b", "c").collect(Collectors.toList());
of方法将一组初始值生成新的Stream。
collect方法将Stream中的值生成一个集合。
2.1.2
public static void main(String[] args) {
List<Integer> src = new ArrayList<>();
for (int i = 0; i < 10; i++)
src.add(i);
List<String> dst = src.stream()
.map(x -> String.valueOf(x))
.collect(Collectors.toList());
}
map中的参数其实是一个Function接口
map方法将参数从一种类型转换为另一种类型,这两种类型可以毫无关系。
2.1.3
List<Integer> dst = src.stream()
.filter(x -> x<10)
.collect(Collectors.toList());
filter的参数是Predicate接口,参数返回boolean。Stream值保留返回true的值。
2.1.4
import java.util.List;
import java.util.stream.Stream;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
List<Integer> list = Stream.of(asList(1, 2), asList(3, 4))
.flatMap(numbers -> numbers.stream())
.collect(toList());
flatmap将多个stream合并为一个stream
2.1.5
int min = Stream.of(1, 2, 3, 4, 5)
.min(Comparator.comparing(x -> x))
.get();
min/max 获取最小/最大值,需要实现Comparator接口
2.1.6
int count = Stream.of(1, 2, 3, 4, 5)
.reduce(0, (acc, element) -> acc+element);
reduce可以将一组值生成一个值,count,min, max都是reduce的一种。
需要注意的是在lamda函数其实是接口,会设计内部方法自动添加final字段
3.1 基本类型
IntSummaryStatistics res = list.stream().mapToInt(x -> x).summaryStatistics();
res.getSum();
res.getMax();
lamda封装了基本类型的操作,可以使用mapToxxx方法进行具体的转换。
调用summaryStatistics方法将返回xxxSummaryStatistics.里面封装了具体的求最大值、最小值、和、平均值等操作。
3.2 @FunctionalInterface
FunctionalInterface注解用于标识lamda接口,将代码块作为数据打包起来。
该注解会强制javac检查一个接口是否符合lamda函数接口的标准。如果该注解添加在枚举、类、另一个注解或者接口不止一个抽象方法,javac会报错。重构代码时,可以很容易发现问题。
3.3 方法引用
//data为Model类型
l//amda表达式片段为
data -> data.get();
//等价于
Model::get
3.4 collect收集器
3.4.1
LinkedBlockingQueue res = list.stream().collect(Collectors.toCollection(LinkedBlockingQueue::new));
Collectors.toCollection方法可以将集合转换为任意Set或Collectoion的子类
3.4.2
求值操作,如求最大值、最小值、平均值。需要注意返回类型。求值操作可以有具体的类型,如averagingInt、averagingXXX
class Model {
private int data;
public int getData() {
return data;
}
public Model(int data){
this.data = data;
}
}
public class Test{
public static void main(String[] args) {
List<Model> list = new ArrayList<>();
for (int i = 0; i < 10; i++)
list.add(new Model(i));
//平均值
double res = list.stream().collect(Collectors.averagingInt(Model::getData));
//求最大值
Optional<Model> d = list.stream().collect(maxBy(comparing(Model::getData)));
}
}
3.4.3
Map<Boolean, List<Model>> res = list.stream().collect(partitioningBy(x -> x.getData() > 5));
partitioningBy可以将一个集合按照条件分割成多个集合
3.4.4
组合收集器,可以将多个操作组合使用。
Map<Integer, Long> res = list.stream().collect(groupingBy(x -> x.getData(), counting()));
groupingBy可以将两个操作一起返回。
x -> x.getData()对应Map的Integer,counting()对应Map的Long
4、并行流处理
普通流调用parallel()或集合调用parallelStream()即可获得一个拥有并行能力的流。
并行处理的性能
数据的大小:并行处理是将数据分割、处理、合并。数据量足够大才能充分体现效率。
源数据结构:
ArrayList、数组或者IntStream支持随机读取的数据结构容易分割。性能较好
HashSet、TreeSet这些不容易分割,但是可以分割。性能一般
LinkedList、Streams.iterate等需要O(N)时间复杂度来分解问题,性能较差
装箱:基本类型比装箱类型效果好
cpu核心数:核心越多,效果越好
单元处理开销:花在流中每个元素的时间越长,效果越好
4.1 并行化数组操作
Arrays.parallelPrefix //计算数组的和
Arrays.parallelSetAll //更新数组元素
Arrays.parallelSort //并行化对数组元素排序
5、调试
使用peek方法可以用于调试打印,不会影响正常的操作
list.stream().peek(natie -> System.out.println("==>"+natie.getData())).count();