说在前面:闲言少叙,正文开始:
书接上文,上一篇文章小名已经带大家简单串了一下JDK8中lambda的一些基础知识。
本文,小名将使用Stream特性写一些例子加深大家的印象,希望可以对大家有所帮助😁
系列文章导航:
- 入门篇
- Stream篇
- 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和集合的区别:
- Stream自己不会存储元素,元素被存储在底层的集合中,或者根据需要产生出来。
- Stream操作符不会改变源对象,方法返回的是新的流。
- Stream操作符是延迟执行的,不调用终端操作,中间的操作不会执行。
- Stream支持并行操作。
四、创建 Stream
创建一个Stream的步骤:
- 通过数据源(如:集合、数组)获取一个流(Stream)
- 在一个或多个步骤中,指定将初始Stream转换为另一个Stream的中间操作。
- 使用一个 终端操作 来产生一个结果。该操作会强制它之前的延迟操作立即执行。
获取两种流:
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篇(内含大量示例代码)
发布评论