java函数式编程入门(个人笔记)

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
nametypedescription
ConsumerConsumer< T >接收T对象,不返回值
PredicatePredicate< T >接收T对象并返回boolean
FunctionFunction< T, R >接收T对象,返回R对象
SupplierSupplier< T >提供T对象(例如工厂),不接收值
UnaryOperatorUnaryOperator< T >接收T对象,返回T对象
BiConsumerBiConsumer<T, U>接收T对象和U对象,不返回值
BiPredicateBiPredicate<T, U>接收T对象和U对象,返回boolean
BiFunctionBiFunction<T, U, R>接收T对象和U对象,返回R对象
BinaryOperatorBinaryOperator< 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);
    }

UnaryOperatorFuntion 有些相似,不同的是它只能返回传入参数同种类型的值

    // 对字符串进行加工
    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);
    }

BiConsumerConsumer 多接收了一个参数

    // 拼接一个名字
    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));
    }

BiPredicatePredicate 多接受一个参数

// 找出年龄较大的一位
    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)

图 1.  流管道 (Stream Pipeline) 的构成


生成 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);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值