Lambda表达式
Lambda 表达式介绍
是没有声明的方法,也即没有访问修饰符、返回值声明和名字。
一般使用场景
当某个方法只使用一次,而且定义很简短,使用这种速记替代之尤其有效。
Lambda 表达式语法
当方法没有形参的时候,使用 () 表示
() -> log.info("hehe");
当方法只有一个形参的时候,可以直接省略括号
p -> log.info("number : {}",p);
当方法有多个参数时,需要使用 () 括起来
(a,b) -> return a + b;
参数可以省略类型,也可以写上
(a,b) -> return a + b;
//等同于
(int a ,int b) -> return a + b;
通过两个例子初步体验 Lambda
创建一个线程
// 原写法
// new Thread(new Runnable() {
// @Override
// public void run() {
// log.info("hello lambda");
// }
// }).start();
// 使用 lambda 表达式创建一个线程
Thread thread = new Thread(() -> log.info("hello lambda"));
thread.start();
实现 List 排序
List<String> list = Arrays.asList(new String[]{"y","z","x"});
// 原写法
// Collections.sort(list, new Comparator<String>() {
// @Override
// public int compare(String o1, String o2) {
// return o1.compareTo(o2);
// }
// });
// 使用 lambda 表达式 完成排序
Collections.sort(list,(o1,o2) -> o1.compareTo(o2));
深入解析 Lambda
Lambda 本身是语法糖,起的作用是重写函数式接口(只包含一个抽象方法声明的接口) 的抽象方法,Java中常用到的比如Comparator或者Runnable接口,这些接口都增加了**@FunctionalInterface** 注解以便能用在lambda上。
// new Runnable 只有 run 一个抽象方法,这里是 Lambda 的语法糖效果,自动重写了这个抽象方法
Thread thread = new Thread(() -> log.info("hello lambda"));
thread.start();
通过一个自定义函数式接口来理解 Lambda
使用 @FunctionalInterface 来声明一个接口是函数式接口,该注解只能标记在**”有且仅有一个抽象方法”的接口上,但它不是必须的**,只是为了编译器更好地检测
//函数式接口
@FunctionalInterface
public interface LambdaInterface {
// 一个求和抽象方法,当然后面重写可以自定义,不一定是求和
public Integer sum(int a ,int b);
}
一个调用这个函数式接口的类
import com.zyy.consumer.bean.User;
import lombok.Data;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
// lombok 中 @Data ,自动填充 setter 和 getter
@Data
public class FirstLambda {
private Integer first;
private Integer second;
public Integer getSum(LambdaInterface lambdaInterface){
return lambdaInterface.sum(first,second);
}
}
开始表演
@Test
public void testLambdaInterface() {
Integer c = 0;
FirstLambda firstLambda = new FirstLambda();
firstLambda.setFirst(22);
firstLambda.setSecond(33);
// 原生态操作
// c = firstLambda.getSum(new LambdaInterface() {
// @Override
// public Integer sum(int a, int b) {
// return a + b;
// }
// });
// 这个时候我们可以使用箭头函数去重写 sum 的实现
c = firstLambda.getSum((a,b) -> {return a + b;});
log.info("number : {}",c);
}
java.util.function 包
使用场景
由于这个包都是 函数式接口,和 Lambda 搭配使用效果更佳
拥有的方法
参考:https://blog.csdn.net/huo065000/article/details/78964382
name | type | description |
---|---|---|
Consumer | Consumer< T > | 接收T对象,不返回值 |
Predicate | Predicate< T > | 接收T对象并返回boolean |
Function | Function< T, R > | 接收T对象,返回R对象 |
Supplier | Supplier< T > | 提供T对象(例如工厂),不接收值 |
UnaryOperator | UnaryOperator< T > | 接收T对象,返回T对象 |
BiConsumer | BiConsumer<T, U> | 接收T对象和U对象,不返回值 |
BiPredicate | BiPredicate<T, U> | 接收T对象和U对象,返回boolean |
BiFunction | BiFunction<T, U, R> | 接收T对象和U对象,返回R对象 |
BinaryOperator | BinaryOperator< T > | 接收两个T对象,返回T对象 |
具体操作
Predicate 用于实现一个条件语句,而 Consumer 用于实现操作,不返回值,两者往往搭配使用
import com.zyy.consumer.bean.User;
import lombok.Data;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
@Data
public class FirstLambda {
private Integer first;
private Integer second;
public Integer getSum(LambdaInterface lambdaInterface){
return lambdaInterface.sum(first,second);
}
// 写一个 筛选list 的方法
public void checkNumberBigger(List<Integer> list,Predicate<Integer> predicate,Consumer<Integer> consumer){
for(Integer integer : list){
if(predicate.test(integer)){
consumer.accept(integer);
}
}
}
}
调用该方法
@Test
public void testLambdaPredicate(){
List<Integer> list = new ArrayList<>();
for(int i = 0 ; i < 10;i++){
list.add(i);
}
// 这里重写了 Predicate 的test 方法,以完成逻辑的判断,重写了 Consumer 的 accept 方法,完成处理操作
new FirstLambda().checkNumberBigger(list,
p -> p > 5,
p -> log.info("number : {}",p));
}
// 此时 Predicate
boolean test(Integer p){
return p > 5 ? true : false;
}
// 此时 Consumer
void accept(Integer p){
log.info("number : {}",p))
}
Function<R,T> 类似一个一元函数,通过输入一个 R 类型的参数,通过处理以后 返回 T 类型的返回值,这里的使用例子是通过输入的字符串 返回 该字符串的长度
// 之前 FirstLambda 中新的方法
public Integer getStringLength(String string,Function<String,Integer> function){
return function.apply(string);
}
// 测试该方法
@Test
public void testFunction(){
FirstLambda firstLambda = new FirstLambda();
Integer length = firstLambda.getStringLength("Hello World",
p -> {return p.length();});
log.info("length : {}",length);
}
Function 中 compose 可以结合两个函数,以下是它的源码
// 可以看出,它是依赖于apply类的,所以这不是一个抽象方法,不影响函数式接口的定义,本质是执行完before 方法以后,继续执行this.apply,从而实现两个函数结合使用
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
实例就采用先进行字符串处理,在计算字符串大小
// 之前 FirstLambda 中新的方法
public Integer getStringLengthSecond(String string,Function<String,String> before,Function<String,Integer> function){
return function.compose((Function<? super String, ? extends String>) before).apply(string);
}
// 测试该方法
@Test
public void testFunctionCompose(){
FirstLambda firstLambda = new FirstLambda();
Integer length = firstLambda.getStringLengthSecond("Hello",
p -> {return p + " World";},
p -> {return p.length();});
log.info("length : {}",length);
}
Function 中 的 andThen 方法则是先执行 this 方法,再去执行 after 方法,也是结合两个Function
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
测试例子是先求字符串的和,再将长度加上100
// 之前 FirstLambda 中新的方法
public Integer getStringLengthThird(String string,Function<Integer,Integer> after,Function<String,Integer> function){
return function.andThen(after).apply(string);
}
// 测试该方法
@Test
public void testFunctionAndThen(){
FirstLambda firstLambda = new FirstLambda();
Integer length = firstLambda.getStringLengthThird("Hello World",
p -> {return p + 100;},
p -> {return p.length();});
log.info("length : {}",length);
}
Supplier 不接受参数,表示一个工厂类,实现工厂的作用,下面是调用User的静态方法返回实例
// User 类
import lombok.Data;
@Data
public class User {
private String name;
private Integer age;
private Double weight;
private String sexy;
private Double height;
public static User getSimpleUser(){
User user = new User();
user.setName("simple");
user.setSexy("male");
user.setAge(21);
return user;
}
}
// 之前 FirstLambda 中新的方法
public User getUser(Supplier<User> supplier){
return supplier.get();
}
// 测试该方法
@Test
public void testSupplier(){
FirstLambda firstLambda = new FirstLambda();
User user = firstLambda.getUser(() -> {return User.getSimpleUser();});
log.info("user : {}",user);
}
UnaryOperator 和 Funtion 有些相似,不同的是它只能返回传入参数同种类型的值
// 对字符串进行加工
public String getString(String string,UnaryOperator<String> unaryOperator){
return unaryOperator.apply(string);
}
// 实现实例
@Test
public void testUnaryOperator(){
FirstLambda firstLambda = new FirstLambda();
String string = firstLambda.getString("Hello",
p -> {return p + " World!!!";});
log.info("string : {}",string);
}
BiConsumer 比 Consumer 多接收了一个参数
// 拼接一个名字
public void getName(String firstName,String secondName,BiConsumer<String,String> biConsumer){
biConsumer.accept(firstName,secondName);
}
//
@Test
public void testBiConsumer(){
FirstLambda firstLambda = new FirstLambda();
firstLambda.getName("Macro","Reus",
(a,b) -> log.info("{} {}",a,b));
}
BiPredicate 比 Predicate 多接受一个参数
// 找出年龄较大的一位
public String getOlderUser(User first,User second,BiPredicate<User,User> biPredicate,Function<User,String> function){
if(biPredicate.test(first,second)){
return function.apply(first);
}else{
return function.apply(second);
}
}
@Test
public void testBiPredicate(){
FirstLambda firstLambda = new FirstLambda();
User first = new User();
first.setName("Ke");
first.setAge(22);
User second = new User();
second.setAge(21);
second.setName("Liang");
// 找出两个User中年龄较大的User的名字
String name = firstLambda.getOlderUser(first,second,
(a,b) -> {return a.getAge() >= b.getAge();},
p -> {return p.getName();});
log.info("user : {}",name);
}
BiFunction 相比于 Function 多接收一个参数
// 计算矩形面积
public Double getArea(Double length,Double width,BiFunction<Double,Double,Double> biFunction){
return biFunction.apply(length,width);
}
//测试实例
@Test
public void testBiFunction(){
FirstLambda firstLambda = new FirstLambda();
Double length = 2.2;
Double width = 5.1;
Double area = firstLambda.getArea(length,width,
(a,b) -> {return a * b;});
log.info("area : {}",area);
}
BinaryOperator 用法同上,只不过只能操作一种类型的参数
Optional 类
实际用处
函数式编程中,用于处理 空指针异常 (NullPointerException)
常用方法
方法 | 说明 |
---|---|
public static Optional of(T value) | 为非null的值创建一个Optional |
public static Optional ofNullable(T value) | 为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional |
public boolean isPresent() | 如果值存在返回true,否则返回false |
public T get() | 如果Optional有值则将其返回,否则抛出NoSuchElementException |
public void ifPresent(Consumer<? super T> consumer) | 如果Optional实例有值则为其调用consumer,否则不做处理 |
public T orElse(T other) | 如果有值则将其返回,否则返回指定的其它值 |
public T orElseGet(Supplier<? extends T> other) | orElseGet与orElse方法类似,区别在于得到的默认值 |
public T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X | 如果有值则将其返回,否则抛出supplier接口创建的异常 |
public Optional map(Function<? super T, ? extends U> mapper) | 如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。 |
public Optional flatMap(Function<? super T, Optional> mapper) | 如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。 |
public Optional filter(Predicate<? super T> predicate) | 如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional |
具体实现
使用 of 创建一个 Optional ,传入的值不能为 NULL,否则抛出 NullPointerException
@Test
public void testOf(){
Optional<String> optional = Optional.of("Ke");
log.info("optional : {}",optional);
}
使用 ofNullable 创建一个 Optional ,如果传入一个 NULL ,则返回空的Optional
@Test
public void testOfNullable(){
Optional<String> optionalFirst = Optional.ofNullable("Liang");
Optional<String> optionalSecond = Optional.ofNullable(null);
log.info("first : {}",optionalFirst); // first : Optional[Liang]
log.info("second ; {}",optionalSecond); // second ; Optional.empty
}
使用 isPresent 判定 Optional 是否为空
@Test
public void testOfNullable(){
Optional<String> optionalFirst = Optional.ofNullable("Liang");
Optional<String> optionalSecond = Optional.ofNullable(null);
log.info("firstIsNull : {}",optionalFirst.isPresent()); // true
log.info("secondIsNull : {}",optionalSecond.isPresent()); // false
}
使用 get 获取值,如果值不存在,抛出 NoSuchElementException
@Test
public void testOfNullable(){
Optional<String> optionalFirst = Optional.ofNullable("Liang");
Optional<String> optionalSecond = Optional.ofNullable(null);
log.info("first : {}",optionalFirst.get()); // first : Liang
log.info("second ; {}",optionalSecond.get()); // java.util.NoSuchElementException: No value present
}
使用 ifPresent 实现函数式编程,如果值存在,则执行 Consumer
@Test
public void testIfPresent(){
Optional<String> optionalFirst = Optional.ofNullable("Liang");
Optional<String> optionalSecond = Optional.ofNullable(null);
optionalFirst.ifPresent(
p -> log.info("firstValue : {}",p) // firstValue : Liang
);
optionalSecond.ifPresent(
p -> log.info("secondValue : {}",p)
);
}
使用 orElse 有值则返回,无值则指定其他值
@Test
public void testOrElse(){
Optional<String> optional = Optional.ofNullable(null);
log.info("optional : {}",optional.orElse("NULL")); // optional : NULL
}
使用 orElseGet 可以结合函数式编程使用,无值则使用 Supplier 工厂返回
@Test
public void testOrElseGet(){
Optional<User> optional = Optional.ofNullable(null);
log.info("optional : {}",optional.orElseGet(
() -> {return User.getSimpleUser();}
));
// optional : User(name=simple, age=21, weight=null, sexy=male, height=null)
}
使用 orElseThrow 结合函数式编程,无值则使用 Supplier 抛出异常
@Test
public void testOrElseThrow(){
Optional<User> optional = Optional.ofNullable(null);
try{
log.info("optional : {}",optional.orElseThrow(
() -> {return new ArithmeticException();}
));
}catch (ArithmeticException a){
log.info("error"); // error
}
}
@Test
public void testOrElseThrow(){
User user = new User();
user.setName("Kabin");
Optional<User> optional = Optional.ofNullable(user);
// optional : User(name=Kabin, age=null, weight=null, sexy=null, height=null)
try{
log.info("optional : {}",optional.orElseThrow(
() -> {return new ArithmeticException();}
));
}catch (ArithmeticException a){
log.info("error");
}
}
使用 map 来结合 Function 实现 对值的处理
@Test
public void testMap(){
Optional<String> optional = Optional.ofNullable("Hello");
// optional : Optional[Hello World!!!]
log.info("optional : {}",optional.map(
p -> {return p + " World!!!";}
));
}
使用 flatMap 来结合 Function,不同的地方在于如果为 NULL,则返回空的 Optional
@Test
public void testFlatMap(){
Optional<String> optional = Optional.ofNullable(null);
// optional : Optional.empty
log.info("optional : {}",optional.map(
p -> {return p + " World!!!";}
));
}
使用 filter 来结合 Predicate 完成过滤处理
@Test
public void testFilter(){
List<Optional<Integer>> list = new ArrayList<>();
for(int i = 0 ;i < 10 ;i ++){
Optional<Integer> optional = Optional.ofNullable(i);
list.add(optional);
}
list.forEach(
p -> log.info("optional : {}",
p.filter(
q -> {return q >=5;}
)
)
);
}
2018-12-16 16:01:24.262 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional.empty
2018-12-16 16:01:24.262 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional.empty
2018-12-16 16:01:24.262 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional.empty
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional.empty
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional.empty
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional[5]
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional[6]
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional[7]
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional[8]
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional[9]
最为有效的用途之一
连环夺命 NULL 判定
@Test
public void testOptional(){
// 获取 User 类中的 name 并且转换为大写,进行 NULL 判定
Optional<User> optional = Optional.ofNullable(User.getSimpleUser());
// name : SIMPLE
log.info("name : {}",
optional.map(
p -> {return p.getName();}
).map(
q -> {return q.toUpperCase();}
).orElse(null)
);
}
@Test
public void testOptional(){
// 获取 User 类中的 name 并且转换为大写,进行 NULL 判定
Optional<User> optional = Optional.ofNullable(null);
// name : null
log.info("name : {}",
optional.map(
p -> {return p.getName();}
).map(
q -> {return q.toUpperCase();}
).orElse(null)
);
}
// 最直观的对比,如果使用 if 来判定,如果判定 null 过程过多时,会写出一堆不雅观的代码,一堆的 if 嵌套
@Test
public String getUser(){
User user = User.getSimpleUser();
if(user != null){
if(user.getName() != null){
return user.getName().toUpperCase();
}else{
return null;
}
}else{
return null;
}
}
Stream 类
详细参考
https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/
关于 Stream
Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。
与 Iterator 的不同
Stream 可以并行化操作,迭代器只能命令式地、串行化操作。Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程。
流管道的结构图
对 Stream 的使用就是实现一个 filter-map-reduce 过程,产生一个最终结果,或者导致一个副作用(side effect)
生成 Stream Source 的方法
- Collection 和 数组:
- Collection.stream()
- Collection.parallelStream()
- Arrays.stream(T array) or Stream.of()
- BufferedReader:
- java.io.BufferedReader.lines()
- 静态工厂:
- java.util.stream.IntStream.range()
- java.nio.file.Files.walk()
- 自己构建:
- java.util.Spliterator
- 其他:
- Random.ints()
- BitSet.stream()
- Pattern.splitAsStream(java.lang.CharSequence)
- JarFile.stream()
流的操作类型
- Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
- Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
- short-circuiting:
- 对于一个 intermediate 操作,如果它接受的是一个无限大(infinite/unbounded)的 Stream,但返回一个有限的新 Stream。
- 对于一个 terminal 操作,如果它接受的是一个无限大的 Stream,但能在有限的时间计算出结果。
Stream 的常见构造
Stream 的 of 可以用于创建,默认是String 类型,如果要创建 Integer,Double,Long,请使用 IntStream, LongStream , DoubleStream ,避免使用泛型可以省去装箱操作,提高性能
@Test
public void testStreamConstruction(){
Stream stream = Stream.of("Ke","Liang","Zeng");
// 不用泛型,使用具体Stream,可以省去 装箱操作,提高性能
IntStream intStream = IntStream.of(22,21,21);
DoubleStream doubleStream = DoubleStream.of(62,55,63);
LongStream longStream = LongStream.of(170,175,170);
}
通过数组构造
@Test
public void testStreamConstructionByArray(){
String[] strings = new String[]{"Ke","Liang","Zeng"};
Stream stream = Stream.of(strings);
stream = Arrays.stream(strings);
}
通过 Collection 来构造
@Test
public void testStreamConstructionByList(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}
// 待探讨,这里无法用 IntStream 接收
Stream<Integer> stream = list.stream();
}
Stream 的操作
现在,我们之前学的 Lambda 就起作用了,因为 Stream 的操作 几乎都是基于 java.utils.function 包来完成的
Stream 的 Intermediate 操作
方法 | 说明 |
---|---|
map | 执行Function操作,修改数值 |
filter | 执行 Predicate操作,完成过滤 |
distinct | 去重 |
sorted | 排序 |
peek | 接收一个Consumer,做一些输出或外部处理 |
limit | 限制Stream通过的个数 |
skip | 跳过前几个 |
parallel | 返回一个 parallel stream(转换为并行流) |
sequential | 返回一个 sequential stream(转换为串行流) |
unordered | 返回一个 unordered stream(转换为无序流) |
Stream 的 Terminal 操作
方法 | 说明 |
---|---|
forEach | 接收一个Consumer |
forEachOrdered | 并行时按顺序处理,区别于forEach |
toArray | 返回一个数组 |
reduce | 接收一个BinaryOperator |
collect | 返回一个集合 |
min | 聚合求最小值 |
max | 聚合求最大值 |
count | 聚合计数 |
anyMatch | 接收一个 Predicate,有一个符合就是True |
allMatch | 接收一个 Predicate,所有符合是Ture |
noneMatch | 接收一个 Predicate,所有不符合是Ture |
findFirst | 获取第一个,返回 Optional,并行流中才和findAny有区别 |
findAny | 随机返回一个,返回 Optional |
iterator | 转换成迭代器 |
Stream 的 Short-circuiting 操作
方法 | 说明 |
---|---|
anyMatch | 同上 |
allMatch | 同上 |
noneMatch | 同上 |
findFirst | 同上 |
findAny | 同上 |
limit | 同上 |
开始表演
map
Stream map(Function<? super T, ? extends R> mapper)
// 将 流的value 全部转为大写,其中的 collect 是返回集合
@Test
public void testStreamMap(){
String[] strings = new String[]{"Ke","Liang","Zeng"};
Stream<String> stream = Stream.of(strings);
List<String> list = stream.map(
p -> p.toUpperCase()
).collect(Collectors.toList());
log.info("list : {}",list); // list : [KE, LIANG, ZENG]
}
filter
Stream filter(Predicate<? super T> predicate) 执行过滤操作
// 将 流的value 小于等于5 的都过滤
@Test
public void testStreamFilter(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}
Stream<Integer> stream = list.stream();
list = stream.filter(
p -> p >5
).collect(Collectors.toList());
log.info("list : {}",list); // list : [6, 7, 8, 9]
}
distinct
Stream distinct() 去重
// 去重
@Test
public void testStreamDistinct(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 3 ; i++){
list.add(i);
}
for(int i = 0 ; i < 3 ; i++){
list.add(i);
}
log.info("before : {}",list); // before : [0, 1, 2, 0, 1, 2]
Stream<Integer> stream = list.stream();
list = stream.distinct().collect(Collectors.toList());
log.info("after : {}",list); // after : [0, 1, 2]
}
sorted
Stream sorted() 和 Stream sorted(Comparator<? super T> comparator)
@Test
public void testStreamSorted(){
Stream<Integer> stream = Stream.of(22,21,21);
// 升序排列
List<Integer> integerList = stream.sorted().collect(Collectors.toList());
log.info("integerList : {}",integerList); // integerList : [21, 21, 22]
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 5 ; i++){
list.add(i);
}
Stream<Integer> streamSecond = list.stream();
// 自定义 CompareTo 完成倒序
list = streamSecond.sorted( (a,b) -> a >= b ? -1 : 1 ).collect(Collectors.toList());
log.info("list : {}",list); // list : [4, 3, 2, 1, 0]
}
peek
Stream peek(Consumer<? super T> action)
@Test
public void testStreamPeek(){
Stream<Integer> stream = Stream.of(22,21,21);
// 一个 Stream 必须执行 Terminal 操作,否则 Intermediate 不起作用
stream.peek(
p -> log.info("number : {}",p)
).count();
}
/*
2018-12-16 17:52:25.639 INFO 7988 --- [ main] com.zyy.consumer.StreamTest : number : 22
2018-12-16 17:52:25.640 INFO 7988 --- [ main] com.zyy.consumer.StreamTest : number : 21
2018-12-16 17:52:25.640 INFO 7988 --- [ main] com.zyy.consumer.StreamTest : number : 21
*/
limit
Stream limit(long maxSize)
// 只需要 3 个元素就足够了
@Test
public void testStreamLimit(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}
Stream<Integer> stream = list.stream();
list = stream.limit(3).collect(Collectors.toList());
log.info("list : {}",list); // list : [0, 1, 2]
}
skip
Stream skip(long n)
// 跳过前三个
@Test
public void testStreamSkip(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}
Stream<Integer> stream = list.stream();
list = stream.skip(3).collect(Collectors.toList());
log.info("list : {}",list); // list : [3, 4, 5, 6, 7, 8, 9]
}
parallel
S parallel() 转换为并行流
@Test
public void testStreamParallel(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 5 ; i++){
list.add(i);
}
Stream<Integer> stream = list.stream();
stream.parallel().forEach(
p -> log.info("number : {}",p)
);
}
2018-12-16 18:16:36.558 INFO 15640 --- [ main] com.zyy.consumer.StreamTest : number : 2
2018-12-16 18:16:36.558 INFO 15640 --- [ main] com.zyy.consumer.StreamTest : number : 4
2018-12-16 18:16:36.560 INFO 15640 --- [ main] com.zyy.consumer.StreamTest : number : 3
2018-12-16 18:16:36.561 INFO 15640 --- [ main] com.zyy.consumer.StreamTest : number : 0
2018-12-16 18:16:36.558 INFO 15640 --- [onPool-worker-1] com.zyy.consumer.StreamTest : number : 1
forEach
void forEach(Consumer<? super T> action)
@Test
public void testStreamForEach(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}
Stream<Integer> stream = list.stream();
stream.limit(3).forEach(
p -> log.info("number : {}",p)
);
}
2018-12-16 18:11:22.170 INFO 14328 --- [ main] com.zyy.consumer.StreamTest : number : 0
2018-12-16 18:11:22.172 INFO 14328 --- [ main] com.zyy.consumer.StreamTest : number : 1
2018-12-16 18:11:22.172 INFO 14328 --- [ main] com.zyy.consumer.StreamTest : number : 2
forEachOrdered
void forEachOrdered(Consumer<? super T> action)
// 并行流也会按顺序执行,不过会牺牲速度
@Test
public void testStreamForEachOrdered(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 5 ; i++){
list.add(i);
}
Stream<Integer> stream = list.stream();
stream.parallel().forEachOrdered(
p -> log.info("number : {}",p)
);
}
2018-12-16 18:20:00.344 INFO 17744 --- [ main] com.zyy.consumer.StreamTest : number : 0
2018-12-16 18:20:00.344 INFO 17744 --- [onPool-worker-1] com.zyy.consumer.StreamTest : number : 1
2018-12-16 18:20:00.345 INFO 17744 --- [onPool-worker-1] com.zyy.consumer.StreamTest : number : 2
2018-12-16 18:20:00.345 INFO 17744 --- [onPool-worker-1] com.zyy.consumer.StreamTest : number : 3
2018-12-16 18:20:00.345 INFO 17744 --- [onPool-worker-1] com.zyy.consumer.StreamTest : number : 4
toArray
Object[] toArray()
@Test
public void testStreamToArray(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}
Stream<Integer> stream = list.stream();
Object[] objects = stream.limit(4).toArray();
for(Object o : objects){
log.info("number : {}",o);
}
}
2018-12-16 18:25:40.322 INFO 5544 --- [ main] com.zyy.consumer.StreamTest : number : 0
2018-12-16 18:25:40.322 INFO 5544 --- [ main] com.zyy.consumer.StreamTest : number : 1
2018-12-16 18:25:40.322 INFO 5544 --- [ main] com.zyy.consumer.StreamTest : number : 2
2018-12-16 18:25:40.322 INFO 5544 --- [ main] com.zyy.consumer.StreamTest : number : 3
reduce
Optional reduce(BinaryOperator accumulator)
// 求和
@Test
public void testStreamReduce(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}
Stream<Integer> stream = list.stream();
Optional<Integer> optional = stream.reduce(
(a,b) -> a + b
);
log.info("sum : {}",optional.get()); // sum : 45
}
Match
// 测试三种 match
@Test
public void testStreamMatch(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}
Stream<Integer> stream = list.stream();
log.info("AnyFirst : {}",stream.anyMatch(
p -> p >5
)); // true
stream = list.stream();
log.info("AnySecond : {}",stream.anyMatch(
p -> p >15
)); // false
stream = list.stream();
log.info("AllFirst : {}",stream.allMatch(
p -> p >=0
)); // true
stream = list.stream();
log.info("AllSecond : {}",stream.allMatch(
p -> p >5
)); // false
stream = list.stream();
log.info("NoneFirst : {}",stream.noneMatch(
p -> p > 10
)); // true
stream = list.stream();
log.info("NoneSecond : {}",stream.noneMatch(
p -> p > 5
)); // false
}
JDK8 中 :: 的使用
本质
就是将 Stream 的参数传入一个方法中执行
要求
- 一个类的静态方法
- 参数需要一致
// LambdaTest 类
@Test
public void testLambdaPredicate(){
List<Integer> list = new ArrayList<>();
for(int i = 0 ; i < 10;i++){
list.add(i);
}
new FirstLambda().checkNumberBigger(list,
p -> p > 5,
LambdaTest::testDoubleQuote); // 将Stream 传入 LambdaTest.testDoubleQuote
new FirstLambda().checkNumberBigger(list,
p -> p > 5,
p -> log.info("number : {}",p));
}
public static void testDoubleQuote(Integer s){
log.info("element : {}",s);
}