来源:blog.csdn.net/qq_41698074/article/details/108502976
前言
虽然 stream在 Java8 中就已经被引入,但是大多数人却没有去使用这个十分有用的特性,本文就通过介绍几个通过使用stream让代码更简洁、可读,来让你了解stream的方便之处。
技巧
数组转集合
相信经常刷LeetCode的小伙伴,偶尔会遇到需要将List与基本类型数组进行互转的情况,然后就需要写像下面这样的代码:
// 将 List 元素存储到数组中
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
int[] arr = new int[list.size()];
Integer[] temp = list.toArray(new Integer[0]);
for (int i = 0; i < temp.length; i++) {
arr[i] = temp[i];
}
// 将数组元素 存储到 List 中
int[] arr = {1, 2, 3, 4, 5};
List<Integer> list = new ArrayList<>();
for (int val : arr) {
list.add(val);
}
以上两个转换虽然写着还不算麻烦,但是每次都需要写一个循环,尤其在数组转List的时候还需要使用一个临时数组,都会让人看着很不舒服,但是如果使用了stream就会大不一样,用stream实现了相同功能的代码如下:
// 将 List 元素存储到数组中
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
int[] arr = list.stream().mapToInt(Integer::intValue).toArray();
// 将数组元素 存储到 List 中
int[] arr = {1, 2, 3, 4, 5};
List<Integer> list = IntStream.of(arr).boxed().collect(Collectors.toList());
可以发现通过使用stream,我们能够在写代码的时候更加连贯,代码也更加可靠易维护,注意力也可以放在业务功能上,相信各位就算对lambda语法并不是太熟悉,在阅读上面代码的时候,也很容易能够看懂。
统计数组元素中的个数
假设我们现在需要统计并输出一个有重复元素的数组中每个元素及对应元素出现的个数,相信各位都能够想到,我们使用一个Map就很容易解决这个问题,代码如下:
String[] arr = {"a", "c", "a", "b", "d", "c"};
Map<String, Integer> map = new HashMap<>();
for (String s : arr) {
if (map.containsKey(s)) {
map.put(s, map.get(s) + 1);
} else {
map.put(s, 1);
}
}
map.forEach((key, value) -> System.out.println(key + " : " + value));
如果对Map中的API更加熟悉的小伙伴,可能会写出下面这个更加简洁的代码:
String[] arr = {"a", "c", "a", "b", "d", "c"};
Map<String, Integer> map = new HashMap<>();
for (String s : arr) {
map.put(s, map.getOrDefault(s, 0) + 1);
}
map.forEach((key, value) -> System.out.println(key + " : " + value));
但是,如果使用stream,我们还能写出更加简洁的代码,同样不需要写烦人的循环了,而且只需两行代码即可(为了提高可读性,进行了换行):
String[] arr = {"a", "c", "a", "b", "d", "c"};
Stream.of(arr)
.collect(Collectors.toMap(k -> k, k -> 1, Integer::sum))
.forEach((k, v) -> System.out.println(k + " : " + v));
注意
在上面的代码中,Collectors.toMap(k -> k, k -> 1, Integer::sum)
这一部分可能不好理解,对于这里面的三个参数,第一个参数代表将arr中的每一个元素作为Map中的key,第二个参数代表每一个key所对应的value,在这里每一个元素都对应个数1,第三个参数代表,如果存在相同的key,该如何进行合并,这里通过使用Integer::sum
,代表将具有相同key的元素进行合并时,其value进行相加,这样便实现了每个元素个数的统计。
基本数据类型的数组自定义排序
有时我们会遇到对基本数据类型的数组进行自定义排序的情况,不同于包装类型的数组和集合可以直接使用比较器,我们只能通过将基本数组类型的数组转为包装类型或者存储在集合中,在排序完成后再转为基本类型的数组,再者,我们只能通过手写排序算法,修改排序算法中的比较进行实现。
不管是哪种方法,我们都没办法将精力放在逻辑功能上,必须写一些额外的代码,甚至是修改底层逻辑,就像下面的代码一样(实现数组逆序):
int[] arr = {1, 5, 9, 7, 2, 3, 7, -1, 0, 3};
// 将数组转为包装类型再进行自定义排序
Integer[] temp = new Integer[arr.length];
for (int i = 0; i < arr.length; i++) {
temp[i] = arr[i];
}
Arrays.sort(temp, Comparator.reverseOrder());
for (int i = 0; i < temp.length; i++) {
arr[i] = temp[i];
}
// 将数组转为集合类型再进行自定义排序
List<Integer> list = new ArrayList<>();
for (int val : arr) {
list.add(val);
}
list.sort(Collections.reverseOrder());
for (int i = 0; i < list.size(); i++) {
arr[i] = list.get(i);
}
// 通过手写排序算法修改比较规则实现
// 为了让代码更加简洁,使用了最暴力且没有优化的冒泡排序
int[] arr = {1, 5