该文章Github地址:https://github.com/AntonyCheng/java-notes【有条件的情况下推荐直接访问GitHub以获取最新的代码更新】
在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template【有条件的情况下推荐直接访问GitHub以获取最新的代码更新】& CSDN文章地址:https://blog.csdn.net/AntonyCheng/article/details/136555245),该模板集成了最常见的开发组件,同时基于修改配置文件实现组件的装载,除了这些,模板中还有非常丰富的整合示例,同时单体架构也非常适合SpringBoot框架入门,如果觉得有意义或者有帮助,欢迎Star & Issues & PR!
上一章:由浅到深认识Java语言(48):Optional类
53.JDK8新特性
前言
到此为止,Java 的基础知识都已经全部展现出来了,但是随着 Java 的更新迭代,Java 不同版本之间会出现一些显著特性,之前有关 Java 基础知识的所有文章均是基于 JDK8 版本所描述的,此后的文章就会推出 JDK8 之后版本的特性介绍。
本章节是“JDK8新特性“,但有一些已经在以往的文章中做出过介绍,它们的文章地址如下:
- 由浅到深认识Java语言(45):Lambda表达式
- 由浅到深认识Java语言(46):Lambda表达式
- 由浅到深认识Java语言(47):Stream流
- 由浅到深认识Java语言(48):Optional类
收集器Collectors
java.util.stream.Collectors
实现了 java.util.stream.Collector
接口,同时又提供了大量的方法对流 ( stream ) 的元素执行 Map And Reduce 操作,或者统计操作,Collectors主要用于 stream.collect()
方法中。
其实在以往的文章中用到过该工具类,例如:
public static void main(String[] args) {
List<Integer> collect = Stream.of(1, 2, 3, 4, 5)
.collect(Collectors.toList());
System.out.println(collect);
}
打印效果如下:
[1, 2, 3, 4, 5]
接下来认识一些更多的常见 API 。
求平均值averagingXXX
avergingXXX()
是一类方法,主要用于在流式计算中获取流中元素的平均值,接下来主要以 averagingDouble()
方法为例。
averagingDouble()
方法将流中的所有元素视为 Double 类型并计算他们的平均值,这些元素均为 Number 类型,计算后的平均值返回为 Double 类型。
public static void main(String[] args) {
Double collect = Stream.of(1f, 2f, 3f, 4f, 5f)
.collect(Collectors.averagingDouble(d -> d));
System.out.println(collect);
}
打印结果如下:
3.0
类似的还有 averagingInt()
、averagingLong()
两个方法,不同点是它们将流中的元素分别视为 Integer 类型和 Long 类型,以及类型之间不可转换的问题。
次序操作collectingAndThen
Collectors.collectingAndThen()
函数应该最像 Map And Reduce 过程,它可接受两个函数式参数,第一个参数用于 Reduce 操作,而第二参数用于 Map 操作,也就是说第二个参数处理完之后的流会传递给第一个参数进行处理,例如现在将一个流中的数字“+1”之后再求平均值:
public static void main(String[] args) {
Double collect = Stream.of(1f, 2f, 3f, 4f, 5f)
.collect(Collectors.collectingAndThen(Collectors.averagingDouble(v -> v),
s -> s + 1));
System.out.println(collect);
}
打印效果如下:
4.0
计数counting
Collectors.counting()
用于统计流中元素的个数,例如:
public static void main(String[] args) {
Long collect = Stream.of(1f, 2f, 3f, 4f, 5f)
.collect(Collectors.counting());
System.out.println(collect);
}
打印效果如下:
5
内容拼接joining
Collectors.joining()
方法用某个指定的拼接字符把所有的字符串流元素拼接成一个字符串,并添加可选的前缀和后缀,例如:
public static void main(String[] args) {
String collect = Stream.of(1, 2, 3, 4, 5)
.map(Object::toString)
.collect(Collectors.joining(",", "prefix", "suffix"));
System.out.println(collect);
}
打印效果如下:
prefix1,2,3,4,5suffix
最值maxBy&minBy
Collectors.maxBy()
和 Collectors.minBy()
两个方法分别用于计算流中所有元素的最大值和最小值。两个方法都可以接受一个比较器作为参数,用于设计如何计算最大值或最小值,例如将字符串转换成字符,然后“+1”,同时转换成字符串,最后计算最大值:
Optional<String> collect = Stream.of("A", "B", "D", "C")
.map(data-> String.valueOf((char) (data.charAt(0) +1)))
.collect(Collectors.maxBy((o1, o2) -> {
return o1.charAt(0) - o2.charAt(0);
}));
System.out.println(collect.get());
打印效果如下:
E
最小值使用方法相同,这里就不进行示例演示。
求累加和summingXXX
summingXXX()
是一类方法,主要用于在流式计算中获取流中元素的累加和,接下来主要以 summingInt()
方法为例。
Collectors.summingInt()
方法将流中的所有元素视为 Integer 类型,并计算所有元素的累加和,返回类型也是 Integer 类型:
public static void main(String[] args) {
Integer collect = Stream.of(1, 2, 3, 4, 5)
.collect(Collectors.summingInt(data -> data));
System.out.println(collect);
}
打印效果如下:
15
类似的还有 summingDouble()
、summingLong()
两个方法,不同点是它们将流中的元素分别视为 Double 类型和 Long 类型,返回值类型也一一对应,以及类型之间不可转换的问题。
转换mapping&flatMapping
Collectors.mapping()
和 Collectors.flatMapping()
可以看作是本质相同,但途径不同的 标准 Map And Reduce 过程。均有两个函数式参数,第一个参数是 Map 操作,第二个参数是 Reduce 操作,途经区别在于 Collectors.mapping()
方法对流中元素每次 Map 操作得到的是一个具体的值,而 Collectors.flatMapping()
方法对流中元素每次 Map 操作得到的是一个与元素相对应的数据流,说简单点即后者具有升维/降维的转换能力,示例如下:
Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 4, 5);
List<Integer> collect1 = integerStream1
.collect(Collectors.flatMapping(data -> {
return Stream.of(data + 1, data * 10);
}, Collectors.toList()));
System.out.println(collect1);
Stream<Integer> integerStream2 = Stream.of(1, 2, 3, 4, 5);
List<Integer> collect2 = integerStream2
.collect(Collectors.mapping(data -> {
return data + 1;
}, Collectors.toList()));
System.out.println(collect2);
打印效果如下:
[2, 10, 3, 20, 4, 30, 5, 40, 6, 50]
[2, 3, 4, 5, 6]
编解码器Base64
Base64 是一种常见的字符编码解码方式,一般用于将二进制数据编码为更具可读性的 Base64 进制格式。
Java 8 中的 java.util.Base64
类提供了三种类型的 Base64 编码解码格式:
1、 简单类型( simple ):编码字符只包含 A-Za-z0-9+/ 等 64 个字符。且编码的时候不会包含任何换行符 ( \r 、 \n 、\r\n )。解码的时候也只会解码 A-Za-z0-9+/ 内的字符,超出的则会被拒绝。
2、 URL:编码字符只包含 A-Za-z0-9+_ 等 64 个字符。和 简单类型 相比,就是把 / 换成了 _ 。因为没有 / 字符,因此这种编码方式非常适合 URL 和文件名等。
3、 MIME:编码会被映射为 MIME 友好格式:每一行输出不超过 76 个字符,而且每行以 \r\n 符结束。但末尾行并不会包含 \r\n。
内部类
java.util.Base64
还包含了两个内部静态类,分别实现了 RFC 4648 和 RFC 2045 中规范的 Base64 编码和解码方式。
内部类 | 说明 |
---|---|
static class Base64.Decoder | 该类实现使用 RFC 4648 和 RFC 2045 中规定的 Base64 解码方案解码数据 |
static class Base64.Encoder | 该类实现使用 RFC 4648 和 RFC 2045 中规定的 Base64 编码方案编码数据 |
静态方法
java.util.Base64
类提供的都是静态方法。下表列出了这些静态方法:
方法 | 说明 |
---|---|
Base64.Decoder getDecoder() | 返回一个 Base64.Decoder 类型的 简单 解码器 |
Base64.Encoder getEncoder() | 返回一个 Base64.Encoder 类型的 简单 编码器 |
Base64.Decoder getMimeDecoder() | 返回一个 Base64.Decoder 类型的 MIME 解码器 |
Base64.Encoder getMimeEncoder() | 返回一个 Base64.Encoder 类型的 MINE 编码器 |
Base64.Encoder getMimeEncoder( int lineLength, byte[] lineSeparator) | 返回一个 Base64.Encoder 类型的使用特定长度和行分隔符的 MINE 编码器 |
Base64.Decoder getUrlDecoder() | 返回一个 Base64.Decoder 类型的 URL 和文件名安全的解码器 |
Base64.Encoder getUrlEncoder() | 返回一个 Base64.Encoder 类型的 URL 和文件名安全的编码器 |
用法示例
这里以简单类型为例:
public static void main(String[] args) {
String str = "Java Notes Of AntonyCHeng";
String encodeStr = Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8));
String decodeStr = new String(Base64.getDecoder().decode(encodeStr));
System.out.println("str = " + str);
System.out.println("encodeStr = " + encodeStr);
System.out.println("decodeStr = " + decodeStr);
}
打印效果如下:
str = Java Notes Of AntonyCHeng
encodeStr = SmF2YSBOb3RlcyBPZiBBbnRvbnlDSGVuZw==
decodeStr = Java Notes Of AntonyCHeng