Java8中两大重要改变。第一个是Lambda表达式,第二是Stream API。
Stream是Java8中处理的抽象概念,它可以对指定的集合进行操作,执行非常复杂的查找、过滤和映射等操作。
使用StreamAPI对集合数据进行操作,就类似于执行sql进行的数据库查询。StreamAPI提供了一种高效且易于使用的处理数据的方式。
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,流讲的是计算。
在开始学习Stream之前,需要先了解一下Lambda表达式。
在了解Lambda表达式之前,需要知道什么是函数式接口。
函数式(Functional Interface)接口是Java8对一类特殊类型的接口的称呼。这类接口只定义了唯一的抽象方法的接口。对于函数式接口来说==@FunctionalInterface== 并不是必须的,只要在接口中只定义了唯一的抽象方法,它实质上就是一个函数式接口,可以用来实现Lambda表达。
在Java8中很出常数式接口都放在java.util.function下面,一般有以下四大核心接口:
接口类型 | 函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|---|
消费型接口 | Consumer《T》 | T | void | 对类型为T的对象应用操作。void accept(T t) |
供给型接口 | Supplier《T》 | 无 | T | 返回类型为T的对象。T get() |
函数型接口 | Function《T,R》 | T | R | 对类型为T的对象执行操作并返回R。R apply(T t) |
断言型接口 | Predicate《T》 | T | boolean | 确定T是否满足条件,返回布尔值。boolean test(T) |
三部分:
// 表达式
(parameters) -> expression
(int a,int b) -> return a + b; //求和
//代码块
(parameters) -> { statements; }
(int a) -> {System.out.println("a = " + a);} //打印,无返回值
(int a) -> {return a * a;} //求平方
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("no use lambda");
}
});
Thread t2 = new Thread(() -> System.out.println("use lambda"));
// 实例
Map<Boolean, List<Integer>> listMap = integers.stream().collect(Collectors.groupingBy(i -> i % 2 == 0)); //根据奇偶性分组
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
for (String feature : features) {
System.out.println(feature); //外部迭代
}
List features = Arrays.asList("Lambdas", "Default Method", "Stream API",
"Date and Time API");
features.stream.forEach(n -> System.out.println(n)); //内部迭代
如果你确定了某个interface是用于Lambda表达式,请一定要加上@FunctionalInterface,表明你的意图。不然将来说不定某个不知情的家伙比如你旁边的好基友,在这个interface上面加了另外一个抽像方法时,你的代码就悲剧了。
private String value = "Enclosing scope value";
public String scopeExperiment() {
Foo fooIC = new Foo() {
String value = "Inner class value";
@Override
public String method(String string) {
return this.value;
}
};
String resultIC = fooIC.method("");
Foo fooLambda = parameter -> {
String value = "Lambda value";
return this.value;
};
String resultLambda = fooLambda.method("");
return "Results: resultIC = " + resultIC +
", resultLambda = " + resultLambda;
}
运行上面这段代码我们将到 resultIC = “Inner class value”,resultLambda = “Enclosing scope value”。也就是说在匿名内部类中this指的是自身的引用,在Lambda表达式中this指的是外部。
5. 多使用方法引用
// 指的是 ::,例如
System.out::prinln
// 优先使用
Foo foo = parameter -> buildString(parameter);
private String buildString(String parameter) {
String result = "Something " + parameter;
//many lines of code
return result;
}
// 而不是
Foo foo = parameter -> { String result = "Something " + parameter;
//many lines of code
return result;
};
多个中间操作可以连起来形成一个流水线,除非流水线上触发终止操作 ,否则中间操作不会执行。而在触发终止操作时,一次性全部处理,称为“惰性求值“。
方法 | 描述 |
---|---|
filter(Predicate p) | 过滤 |
distinct() | 通过对象重写的hascode和equals去重 |
limit(long maxSize) | 截断,获取指定数量元素 |
skip(long n) | 跳过,与limit(n))互补 |
方法 | 描述 |
---|---|
map(Function f) | 接受一个函数,应用到每个元素,并将其映射成一个新的元素 |
flatMap(Function f) | 接受一个函数,将流中的每一个值换成另一个流,然后把所有的流连接成一个流 |
/**
* 测试map跟flatMap的区别
* 有点跟集合中的add跟addAll方法类似
* add是将无论是元素还是集合,整体加到其中一个集合中去[1,2,3.[2,3]]
* addAll是将无论是元素还是集合,都是将元素加到另一个集合中去。[1,2,3,2,3]
*/
方法 | 描述 |
---|---|
sorted() | 自然顺序排序 |
sorted(Comparator comp) | 自定义比较器 |
终止操作会从流水线产生结果。其结果可以是List、Integer甚至是void
方法 | 描述 |
---|---|
allMatch(Predcate p) | 检查是否全部匹配 |
anyMatch(Predcate p) | 。。。 |
nontMatch(Predcate p) | … |
findFirst() | 返回第一个元素 |
findAny() | 返回任意元素 |
count() | 统计 |
max(Comparator c) | 返回最大 |
forEach(Consumer c) | 内部迭代,取代外部跌打 |
方法 | 描述 |
---|---|
reduce(T iden,BinaryOperate b) | 可以将流中元素反复结合起来,得到一个值,返回T |
reduce(BinaryOperate b) | 同上,返回Optional《T》 |
方法 | 描述 |
---|---|
collect(Collector c) | 将流转换为其他形式,接收一个Collector接口的实现,用于给流中的元素做汇总的方法 |
Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体请参阅文档。
https://github.com/zhaoteng8069/springboot-demo.git
https://www.jianshu.com/p/8e3b8a483bd8
https://www.cnblogs.com/linlinismine/p/9283532.html