说在前面:
书接上文,上一篇文章小名已经带大家简单串了一下JDK8中lambda的一些基础知识。
本文,小名将使用Stream特性写一些例子加深大家的印象,希望可以对大家有所帮助😁
闲言少叙,正文开始:

系列文章导航:

  1. 入门篇
  2. Stream篇
  3. StreamAPI篇

持续更新中……


文章目录

        • 一、Java 内置四大核心函数式接口
          • 前瞻表格
          • 1. Consumer<T> 消费型接口
          • 2. Supplier<T> 供给型接口
          • 3. Function<T, R> 函数型接口
          • 4. Predicate<T> 断言型接口
        • 二、其他接口
          • 前瞻表格
          • 1. BiFunction<T, U, R>
          • 2. UnaryOperator<T>
          • 3. BinaryOperator<T>
          • 4. BiConsumer<T,U>
          • 5. To X Function<T>
          • 6. XFunction<R>
        • 三、什么是Stream
        • 四、创建 Stream
        • 五、Stream 的串行与并行
          • 1. 获取串行流:
          • 2. 获取并行流:
        • 六、Optional类型
          • 1. empty()
          • 2. of()
          • 3. ofNullable()
          • 4. isPresent()
          • 5. get()
          • 6. ifPresent()
          • 7. orElse()
          • 8. orElseGet(Supplier< ? extends T> other)
          • 9. orElseThrow()


一、Java 内置四大核心函数式接口

前瞻表格

内置的四大核心函数式接口

函数式接口

抽象方法

介绍

Consumer

void accept(T t);

消费型接口

Supplier

T get();

供给型接口

Function<T,R>

R apply(T t);

函数型接口

Predicate

boolean test(T t);

断言型接口

 

1. Consumer<T> 消费型接口

只对方法入参进行操作,没有返回值,包含方法:void accept(T t);

public class ConsumerEx {
    public void ConsumerTestMethod(Consumer<String> str) {
        str.accept("Hello world");
    }

    public void ConsumerTestMethod2(Consumer<Integer> num) {
        num.accept(10);
    }

    @Test
    public void ConsumerTest() {
        ConsumerTestMethod(e -> System.out.println(e + " Consumer"));

        ConsumerTestMethod2(e -> {
            e = e + 10;
            System.out.println(e);
        });
    }
}

//输出:
//Hello world Consumer
//20
2. Supplier<T> 供给型接口

返回一个类型为T的对象,包含方法:T get();

public class SupplierEx {

    public Integer SupplierTestMethod(Supplier<Integer> num){
        return num.get();
    }

    public String SupplierTestMethod2(Supplier<String> str){
        return str.get();
    }

    @Test
    public void SupplierTest(){
        Integer integer = SupplierTestMethod(() -> 10);
        System.out.println(integer);

        String s = SupplierTestMethod2(() -> "Hello!");
        System.out.println(s);
    }
}

//输出:
//10
//Hello!
3. Function<T, R> 函数型接口

对入参T类型对象进行操作,并返回R类型的对象,包含方法:R apply(T t);

public class FunctionEx {

    public String FunctionTestMethod(Function<Integer, String> fun, Integer num) {
        return fun.apply(num);
    }

    @Test
    public void FunctionTest() {
        String s = FunctionTestMethod(e -> e + "这个数字变成字符串了", 10);
        System.out.println(s);
    }
}

//输出
//10这个数字变成字符串了
4. Predicate<T> 断言型接口

判断类型T的对象是否满足某约束,并返回boolean 值。包含方法:boolean test(T t);

public class PredicateEx {

    public Boolean PredicateTestMethod(Predicate<String> predicate, String str) {
        return predicate.test(str);
    }

    @Test
    public void PredicateTest() {
        Boolean flag = PredicateTestMethod(str -> {
            if (str.length() > 0) {
                return true;
            } else {
                return false;
            }
        }, "我是Predicate的测试");

        System.out.println(flag);
    }
    
}

//输出:
//true

二、其他接口

前瞻表格

其他接口

函数式接口

抽象方法

介绍

BiFunction<T,U,R>

R apply(T t,U u);

对入参类型为 T,U的对象进行操作,返回R类型的结果。

UnaryOperator

T apply(T t);

对入参类型为 T的对象进行一元运算,并返回T类型的结果。

BinaryOperator

T apply(T t1,T t2);

对入参类型为 T的对象进行二元运算,并返回T类型的结果。

BiConsumer<T,U>

void accept(T t,U u)

对入参类型为 T,U参数应用操作,无返回值。

ToIntFunction

ToLongFunction

ToDoubleFunction

int applyAsInt(T value);

long applyAsLong(T value);

double applyAsDouble(T value);

分别计算 int、long、double、值的函数。

IntFunction

LongFunction

DoubleFunction

R apply(int value);

R apply(double value);

R apply(long value);

接受 int、double、long类型的入参并产生结果的函数。

 

1. BiFunction<T, U, R>

对入参类型为 T, U 的对象进行操作, 返回 R 类型的结果。

public String BiFunctionTestMethod(BiFunction<Integer, Integer, String> biFunction, Integer a, Integer b) {
    return biFunction.apply(a, b);
}

@Test
public void BiFunctionTest() {
    String s = BiFunctionTestMethod((x, y) -> {
        Integer sum = x + y;
        String str = "两数之和为:";
        return str + sum;
    }, 10, 5);

    System.out.println(s);
}
2. UnaryOperator<T>

对入参类型为 T 的对象进行一元运算,并返回T类型的结果。

public Integer UnaryOperatorTestMethod(UnaryOperator<Integer> unaryOperatorEx, Integer a){
    return unaryOperatorEx.apply(a);
}

@Test
public void UnaryOperatorTest(){
    Integer integer = UnaryOperatorTestMethod(e -> e + 20, 10);
    System.out.println(integer);
}
3. BinaryOperator<T>

对入参类型为 T 的对象进行二元运算,并返回T类型的结果。

public Integer BinaryOperatorTestMethod(BinaryOperator<Integer> binaryOperator,Integer a,Integer b){
    return binaryOperator.apply(a,b);
}

@Test
public void BinaryOperatorTest(){
    Integer integer = BinaryOperatorTestMethod((x, y) -> x * y, 3, 9);
    System.out.println(integer);
}
4. BiConsumer<T,U>

对入参类型为T, U 参数应用操作,无返回值。

public void BiConsumerTestMethod(BiConsumer<String,Integer> biConsumer,String str,Integer num){
    biConsumer.accept(str,num);
}

@Test
public void BiConsumerTest(){
    BiConsumerTestMethod((s,n)-> System.out.println(s+n),"输入的数字是:",155);
}
5. To X Function<T>

分别计算 int、long、double、值的函数。

/**
 * ToIntFunction<T>
 * 计算int值的函数
 */
public Integer ToIntFunctionTestMethod(ToIntFunction<String> toIntFunction, String a) {
    return toIntFunction.applyAsInt(a);
}

/**
 * ToLongFunction<T>
 * 计算long值的函数
 */
public Long ToLongFunctionTestMethod(ToLongFunction<String> toLongFunction, String a) {
    return toLongFunction.applyAsLong(a);
}

/**
 * ToDoubleFunction<T>
 * 计算double值的函数
 */
public Double ToDoubleFunctionTestMethod(ToDoubleFunction<Integer> toDoubleFunction, Integer a) {
    return toDoubleFunction.applyAsDouble(a);
}


@Test
public void ToXFunctionTest() {
    System.out.println("---------↓--ToInteger--↓---------");
    Integer integer = ToIntFunctionTestMethod(e -> Integer.valueOf(e), "15");
    System.out.println(integer);

    System.out.println("---------↓--ToLong--↓---------");
    Long aLong = ToLongFunctionTestMethod(l -> Long.parseLong(l), "12345654892516561");
    System.out.println(aLong);

    System.out.println("---------↓--ToDouble--↓---------");
    Double aDouble = ToDoubleFunctionTestMethod(i -> i * 1.0, 5);
    System.out.println(aDouble);
}
6. XFunction<R>

接受 int、double、long 类型的入参并产生结果的函数。

/**
 * DoubleFunction<R>
 * 参数为double类型的函数
 */
public String DoubleFunctionTestMethod(DoubleFunction<String> doubleFunction,Double d){
    return doubleFunction.apply(d);
}

/**
 * IntFunction<R>
 * 参数为int类型的函数
 */
public String IntFunctionTestMethod(IntFunction<String> intFunction,Integer a){
    return intFunction.apply(a);
}

/**
 * LongFunction<R>
 * 参数为long类型的函数
 */
public String LongFunctionTestMethod(LongFunction<String> longFunction,Long l){
    return longFunction.apply(l);
}

@Test
public void XFunctionTest(){
    System.out.println("---------↓--Integer--↓---------");
    String s = IntFunctionTestMethod(a -> "输入的数字为:" + a, 5);
    System.out.println(s);

    System.out.println("---------↓--Doublie--↓---------");
    String s1 = DoubleFunctionTestMethod(d -> "输入的数字为:" + d, 66.0);
    System.out.println(s1);

    System.out.println("---------↓--Long--↓---------");
    String s2 = LongFunctionTestMethod(l -> "输入的数字为:" + l, 151915616516516516L);
    System.out.println(s2);
}

三、什么是Stream

流(Stream) 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。简单来说:“集合讲的是数据,流讲的是计算。”

Stream和集合的区别:

  1. Stream自己不会存储元素,元素被存储在底层的集合中,或者根据需要产生出来。
  2. Stream操作符不会改变源对象,方法返回的是新的流。
  3. Stream操作符是延迟执行的,不调用终端操作,中间的操作不会执行。
  4. Stream支持并行操作。

四、创建 Stream

创建一个Stream的步骤:

  1. 通过数据源(如:集合、数组)获取一个流(Stream)
  2. 在一个或多个步骤中,指定将初始Stream转换为另一个Stream的中间操作
  3. 使用一个 终端操作 来产生一个结果。该操作会强制它之前的延迟操作立即执行。

获取两种流:
default Stream stream() : 返回一个顺序流
default Stream parallelStream() : 返回一个并行流

五、Stream 的串行与并行

1. 获取串行流:
  • 通过stream()方法获取流
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
  • 通过 Stream 接口的静态方法of()可以获取对应的流
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
2. 获取并行流:
  • 将串行流调用 parallel() 转成并行流:
ArrayList<Integer> list = new ArrayList<>();
Stream<Integer> stream = list.stream().parallel();
  • 通过 parallelStream() 获取并行的流:
ArrayList<Integer> list2 = new ArrayList<>();
Stream<Integer> stream1 = list2.parallelStream();

并行流的效率是要比串行流要高,底层使用Fork/Join框架进行处理,能充分利用 CPU 的多核能力,Stream 的 API 将底层复杂实现完全屏蔽了,开发者仅需调用一个方法即可实现并行计算。

@Test
public void speedComparison() {
    // 并行计算
    long startTime = System.currentTimeMillis();
    //TODO
    long sum = LongStream.rangeClosed(1, 1000000000L).parallel().sum();
    System.out.println("并行执行耗时:" + (System.currentTimeMillis() - startTime));

    // 串行计算
    startTime = System.currentTimeMillis();
    //TODO
    long sum1 = LongStream.rangeClosed(1, 1000000000L).sum();
    System.out.println("串行执行耗时:" + (System.currentTimeMillis() - startTime));

    System.out.println("串行求和结果="+sum+"     "+"并行求和结果="+sum1);
}

//输出:
//并行执行耗时:157
//串行执行耗时:399
//串行求和结果=500000000500000000     并行求和结果=500000000500000000

在适当的条件下,通过调用 parallel() 方法,确实可以在多核理器的情况下实现近乎线性的倍增。但如上面这个例子,若是数值范围小的情况下,并行流反而需要的时间比串行流多,所以请视业务情况而定谨慎使用。

六、Optional类型

Java8 中引入了 Optional 类来解决 NullPointerException 与繁琐的 null 检查,Optional 类是一个可以为 null 的容器对象。值存在则 isPresent() 方法会返回 true,调用 get() 方法会返回该对象。

Optional类常用方法

empty()

创建一个空的 Optional 对象

of()

依据一个非空值,创建一个 Optional 对象

ofNullable()

创建一个允许 null 值的 Optional 对象

get()

获取 Optional 实例中的值

isPresent()

如果值存在则返回 true,否则返回 false(与get()组合使用可避免 NullPointerException)

ifPresent(Consumer consumer)

该方法会接收一个消费型函数。当 Optional 中的变量不为空时,会调用实现 Supplier 接口的方法或Lambda表达式来返回默认值, 若为空则不做处理

orElse()

定义一个默认值,当 Optional 中的变量为空时,默认值会作为该方法的返回值,反之返回值。

orElseGet(Supplier other)

Optional 中的变量为空时,会调用实现 Supplier 接口的方法或Lambda表达式来返回默认值,反之返回值。

orElseThrow()

如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常

 

1. empty()

创建Optional对象

Optional<Object> empty = Optional.empty();
empty.get();

注:当空 Optional 对象调用get()会报错

java.util.NoSuchElementException: No value present
2. of()

创建Optional非空对象

Person personNull = null;
Person person = new Person("张三", 32, "男", true);

Optional<Person> person1 = Optional.of(person);

注:当传入的参数是 null,会抛出异常 NullPointerException,如下

Optional<Person> person1 = Optional.of(personNull);

//报错
java.lang.NullPointerException
3. ofNullable()

创建一个允许 null 值的 Optional 对象

Optional<Person> personNull1 = Optional.ofNullable(personNull);
4. isPresent()

如果值存在则返回true,否则返回 false(与get()组合使用可避免 NullPointerException)

boolean present = person1.isPresent();
System.out.println(present); //输出:true
5. get()

获取 Optional 实例中的值

Person getPerson = person1.get();
System.out.println(getPerson); //输出:Person{name='张三', age=32, sex='男', business=true}
6. ifPresent()

当 Optional 中的变量不为空时,会调用实现 Supplier 接口的方法或Lambda表达式来返回默认值,若为空则不做处理。

person1.ifPresent(e-> System.out.println("我不是空对象"));
7. orElse()

定义一个默认值,当 Optional 中的变量为空时,默认值会作为该方法的返回值,反之返回值。

personNull1.orElse(new Person("李四", 62, "男", false));
8. orElseGet(Supplier< ? extends T> other)

当 Optional 中的变量为空时,会调用实现 Supplier 接口的方法或Lambda表达式来返回默认值,反之返回值。

personNull1.orElseGet(() -> new Person("李四", 62, "男", false));
9. orElseThrow()

如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常

personNull1.orElseThrow(() -> new NoSuchElementException());

如若您在文章中发现任何错误的地方,希望您可以在评论区给予小名批评指正🤝 如果觉得小名的文章帮助到了您,请关注小名的专栏【Java8】,支持一下小名😄,给小名的文章点赞👍、评论✍、收藏🤞谢谢大家啦~♥♥♥

更多推荐

一直想弃用,从未被替代的Java8——Stream篇(内含大量示例代码)