共计 3732 个字符,预计需要花费 10 分钟才能阅读完成。
起源: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, 9, 7, 2, 3, 7, -1, 0, 3};
for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr.length - i - 1; j++) {if (arr[j] < arr[j + 1]) {int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
能够发现以上几种办法,咱们都须要写很多代码,无奈将注意力集中在设计自定义排序这个问题上,然而通过应用 stream,咱们就能够写出上面这样简洁的代码 (如果违心的话,你也能够把一系列的链式操作写在一行上,但为了代码的可读性,不倡议那么做):
int[] arr = {1, 5, 9, 7, 2, 3, 7, -1, 0, 3};
arr = IntStream.of(arr)
.boxed()
.sorted(Comparator.reverseOrder())
.mapToInt(Integer::intValue)
.toArray();
留神
在这里其实为了实现数组的逆序,咱们只须要调用 Arrays 的 sort 办法,而后再进行数组元素的反转即可,不过因为是为了解说自定义排序,大多数状况下不会是数组逆序这么简略,所以我就写了更加通用一些的代码。
统计数组中前 k 个个高频元素
在最初,咱们通过一道题来进行实战以便更好的体验 stream 的弱小之处,当然咱们在练习该题的时候,更须要从算法的角度去思考该题的解法,不过在本文,咱们次要为了解说 stream 的应用,所以就不去思考算法的货色了,而如果应用 stream,咱们就能够写出上面这样简略易懂的代码:
class Solution {public int[] topKFrequent(int[] nums, int k) {return Arrays.stream(nums)
.boxed()
.collect(Collectors.toMap(e -> e, e -> 1, Integer::sum))
.entrySet()
.stream()
.sorted((m1, m2) -> m2.getValue() - m1.getValue())
.limit(k)
.mapToInt(Map.Entry::getKey)
.toArray();}
}
总结
本文介绍了几个简略、实用的 stream 应用技巧,当然 stream 的利用远不止此,心愿通过本文,可能激发起你学习 stream 的趣味,本文若有谬误之处,也欢送你的斧正。
近期热文举荐:
1.1,000+ 道 Java 面试题及答案整顿 (2022 最新版)
2. 劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!
5.《Java 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!