Java 中 Map 的5种遍历方式

同系列文章
java 中 List 的5种遍历方式
Java 中 Set 的4中遍历方式
Java 中 Map 的5种遍历方式
主测试方法

  1. @Test
  2. public void test1(){
  3. Map<Integer, Integer> map = new HashMap<Integer, Integer>();
  4. int n = 1000_0000;
  5. for (int i = 1; i <= n; i++) {
  6. map.put(i, i);
  7. }
  8. System.out.println("======== 1 entrySet 最常用 ==========");
  9. entrySetTest(map);
  10. System.out.println("======== 2 keySet Or Values 取keys或values 时,效率最高 ==========");
  11. keySetOrValuesTest(map);
  12. //System.out.println("======== keySetForValueTest ==========");
  13. keySetForValueTest(map);
  14. System.out.println("======== 3 iterator Type ==========");
  15. iteratorTypeTest(map);
  16. System.out.println("======== 4 forEach java 8 效率最低 ==========");
  17. forEachTest(map);
  18. System.out.println("======== 5 stream ForEach java 8 流式 ==========");
  19. streamForEachTest(map);
  20. }

1000万数据测试结果
======== 1 entrySet 最常用 ==========
map.entrySet() time= 65

======== 2 keySet Or Values 取keys或values 时,效率最高 ==========
map.keySet() time= 71
map.keySet().iterator() time= 63
map.values() time= 74
map.values().iterator() time= 64
map.keySet() -> map.get(key) time= 107

======== 3 iterator Type ==========
map.entrySet().iterator() time= 85

======== 4 forEach java 8 效率最低 ==========
map.forEach time= 103

======== 5 stream ForEach java 8 流式 ==========
map.entrySet().stream().forEach time= 62

1、最常用的方法,map.entrySet() 加增强for

  1. /**
  2. * 1
  3. * entrySet 这是最常用的方式,在键值都需要的时候
  4. * @param map
  5. */
  6. public void entrySetTest(Map<Integer, Integer> map){
  7. long before = System.currentTimeMillis();
  8. for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
  9. entry.getKey();
  10. entry.getValue();
  11. // System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
  12. }
  13. long after = System.currentTimeMillis();
  14. System.out.println("map.entrySet() time=\t" + (after - before));
  15. }

2、通过keySet() 或 values()获取

  1. /**
  2. * 2(1)keySet values
  3. * 如果只需要键或者值,这个比键值对的要快
  4. * @param map
  5. */
  6. public void keySetOrValuesTest(Map<Integer, Integer> map){
  7. long before = System.currentTimeMillis();
  8. // 遍历map中的键
  9. for (Integer key : map.keySet()) {
  10. //System.out.println("Key = " + key);
  11. }
  12. long after = System.currentTimeMillis();
  13. System.out.println("map.keySet() time=\t" + (after - before));
  14. before = System.currentTimeMillis();
  15. // 遍历map中的键
  16. Iterator<Integer> iteratorKeySet = map.keySet().iterator();
  17. while (iteratorKeySet.hasNext()) {
  18. iteratorKeySet.next();
  19. //System.out.println("key = " + iteratorKeySet.next());
  20. }
  21. after = System.currentTimeMillis();
  22. System.out.println("map.keySet().iterator() time=\t" + (after - before));
  23. before = System.currentTimeMillis();
  24. // 遍历map中的值
  25. for (Integer value : map.values()) {
  26. //System.out.println("Value = " + value);
  27. }
  28. after = System.currentTimeMillis();
  29. System.out.println("map.values() time=\t" + (after - before));
  30. before = System.currentTimeMillis();
  31. // 遍历map中的值
  32. Iterator<Integer> iteratorValues = map.values().iterator();
  33. while (iteratorValues.hasNext()) {
  34. iteratorValues.next();
  35. //System.out.println("key = " + iterator.next());
  36. }
  37. after = System.currentTimeMillis();
  38. System.out.println("map.values().iterator() time=\t" + (after - before));
  39. }
  40. /**
  41. * 2(2)keySet get
  42. * 根据键找值,效率很低
  43. * @param map
  44. */
  45. public void keySetForValueTest(Map<Integer, Integer> map){
  46. long before = System.currentTimeMillis();
  47. //遍历map中的键
  48. for (Integer key : map.keySet()) {
  49. Integer value = map.get(key);
  50. //System.out.println("Key = " + key + ", Value = " + value);
  51. }
  52. long after = System.currentTimeMillis();
  53. System.out.println("map.keySet() -> map.get(key) time=\t" + (after - before));
  54. }

3、通过迭代器 map.entrySet().iterator()

  1. /**
  2. * 3(1)iterator type
  3. * 迭代器 带泛型
  4. * @param map
  5. */
  6. public void iteratorTypeTest(Map<Integer, Integer> map){
  7. long before = System.currentTimeMillis();
  8. Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
  9. while (entries.hasNext()) {
  10. Map.Entry<Integer, Integer> entry = entries.next();
  11. Integer key = entry.getKey();
  12. Integer value = entry.getValue();
  13. //System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
  14. }
  15. long after = System.currentTimeMillis();
  16. System.out.println("map.entrySet().iterator() time=\t" + (after - before));
  17. }

4、map.forEach 注意:java8 才支持

  1. /**
  2. * 4 forEach 遍历的是键值,所以是两个参数
  3. * forEach java8 lambda
  4. * @param map
  5. */
  6. public void forEachTest(Map<Integer, Integer> map){
  7. long before = System.currentTimeMillis();
  8. //map.forEach( (key,value) -> {System.out.println("Key = " + key+ ", Value = "+ value);} );
  9. map.forEach( (key,value) -> {} );
  10. long after = System.currentTimeMillis();
  11. System.out.println("map.forEach time=\t" + (after - before));
  12. // 一条语句可以省略{}
  13. //map.forEach( (key,value) -> System.out.println("Key = " + key+ ", Value = "+ value) );
  14. }

5、map.entrySet().stream().forEach 注意:java8 才支持

  1. /**
  2. * 5 stream forEach 遍历的是entry 所以是一个参数
  3. * stream forEach java8 lambda
  4. * @param map
  5. */
  6. public void streamForEachTest(Map<Integer, Integer> map){
  7. long before = System.currentTimeMillis();
  8. //map.entrySet().stream().forEach( (entry) -> {System.out.println("Key = " + entry.getKey()+ ", Value = "+ entry.getValue());} );
  9. //map.entrySet().stream().forEach( System.out::println);
  10. map.entrySet().stream().forEach( (entry) -> {} );
  11. long after = System.currentTimeMillis();
  12. System.out.println("map.entrySet().stream().forEach time=\t" + (after - before));
  13. // 一个参数可以省略() 一条语句可以省略{}
  14. //map.entrySet().stream().forEach(entry -> System.out.println("Key = " + entry.getKey()+ ", Value = "+ entry.getValue()) );
  15. }

String、String[]、ArrayList之间的转换

  1. ArrayList 转换为 String[]:
      ArrayList list = new ArrayList<>();
      list.add(“aaa”);
      list.add(“bbb”);
      String[] arrString = list.toArray(new String[list.size()]) ;
  2. String[] 转换为 ArrayList:
      ArrayList list = new ArrayList<> (new String[] { “aaa”, “bbb” });
  3. ArrayList 转换为 String:
      ArrayList list = new ArrayList<>();
      list.add(“aaa”);
      list.add(“bbb”);
      String str = String.join(“,”, list.toArray(new String[list.size()]));
  4. String 转换为 ArrayList :
      String str =”1,2,3,4,5”;
      ArrayList b = new ArrayList( str.split(‘,’) ) ;

StringJoiner-字段串拼接

要高效拼接字符串,应该使用StringBuilder。
很多时候,我们拼接的字符串像这样:
// Hello Bob, Alice, Grace!
无法连接到Java代码运行助手。请检查本机的设置。
类似用分隔符拼接数组的需求很常见,所以Java标准库还提供了一个StringJoiner来干这个事:
import java.util.StringJoiner;
慢着!用StringJoiner的结果少了前面的”Hello “和结尾的”!”!遇到这种情况,需要给StringJoiner指定“开头”和“结尾”:
import java.util.StringJoiner;
那么StringJoiner内部是如何拼接字符串的呢?如果查看源码,可以发现,StringJoiner内部实际上就是使用了StringBuilder,所以拼接效率和StringBuilder几乎是一模一样的。
String.join()

String还提供了一个静态方法join(),这个方法在内部使用了StringJoiner来拼接字符串,在不需要指定“开头”和“结尾”的时候,用String.join()更方便:
String[] names = {“Bob”, “Alice”, “Grace”};
var s = String.join(“, “, names);
练习

请使用StringJoiner构造一个SELECT语句:
import java.util.StringJoiner;

public class Main {
public static void main(String[] args) {
String[] fields = { “name”, “position”, “salary” };
String table = “employee”;
String select = buildSelectSql(table, fields);
System.out.println(select);
System.out.println(“SELECT name, position, salary FROM employee”.equals(select) ? “测试成功” : “测试失败”);
}
}
下载练习:StringJoiner练习 (推荐使用IDE练习插件快速下载)
小结

用指定分隔符拼接字符串数组时,使用StringJoiner或者String.join()更方便;
用StringJoiner拼接字符串时,还可以额外附加一个“开头”和“结尾”。

RandomStringUtils工具类的使用/随机数

  1. //产生5位长度的随机字符串,中文环境下是乱码
  2.   RandomStringUtils.random(5);
  3.   //使用指定的字符生成5位长度的随机字符串
  4.   RandomStringUtils.random(5, new char[]{‘a’,‘b’,‘c’,‘d’,‘e’,‘f’, 1’, 2’, 3’});
  5.   //生成指定长度的字母和数字的随机组合字符串
  6.   RandomStringUtils.randomAlphanumeric(5);
  7.   //生成随机数字字符串
  8.   RandomStringUtils.randomNumeric(5);
  9.   //生成随机[a-z]字符串,包含大小写
  10.   RandomStringUtils.randomAlphabetic(5);
  11.   //生成从ASCII 32到126组成的随机字符串
  12.   RandomStringUtils.randomAscii(4)
  13.   /*count 创建一个随机字符串,其长度是指定的字符数,字符将从参数的字母数字字符集中选择,如参数所示。
  14.    * letters true,生成的字符串可以包括字母字符
  15.    * numbers true,生成的字符串可以包含数字字符
  16.    */
  17.   String random = RandomStringUtils.random(15, true, false);
  18. /**
  19.    * 创建一个随机字符串,其长度是指定的字符数。
  20.    * 将从所有字符集中选择字符
  21.    */
  22.   random = RandomStringUtils.random(22);
  23.   /**
  24.    * 创建一个随机字符串,其长度是指定的字符数。
  25.    * 字符将从字符串指定的字符集中选择,不能为空。如果NULL,则使用所有字符集。
  26.    */
  27.   random = RandomStringUtils.random(15, abcdefgABCDEFG123456789”);
  28.   /**
  29.    * 创建一个随机字符串,其长度是指定的字符数,字符将从参数的字母数字字符集中选择,如参数所示。
  30.    * count:计算创建的随机字符长度
  31.    * start:字符集在开始时的位置
  32.   * end:字符集在结束前的位置,必须大于65
  33.    * letters true,生成的字符串可以包括字母字符
  34.    * numbers true,生成的字符串可以包含数字字符
  35.    */
  36.   random = RandomStringUtils.random(1009, 5, 129, true, true);
  37.   /**
  38.    * 产生一个长度为指定的随机字符串的字符数,字符将从拉丁字母(a-z、A-Z的选择)。
  39.    * count:创建随机字符串的长度
  40.    */
  41.   random = RandomStringUtils.randomAlphabetic(15);
  42.   /**
  43.    * 创建一个随机字符串,其长度介于包含最小值和最大最大值之间,,字符将从拉丁字母(a-z、A-Z的选择)。
  44.    * minLengthInclusive :要生成的字符串的包含最小长度   * maxLengthExclusive :要生成的字符串的包含最大长度
  45.    */
  46.   random = RandomStringUtils.randomAlphabetic(2, 15);
  47.   /**
  48.   * 创建一个随机字符串,其长度是指定的字符数,字符将从拉丁字母(a-z、A-Z)和数字0-9中选择。
  49.   * count :创建的随机数长度
  50.   */
  51.   random = RandomStringUtils.randomAlphanumeric(15);
  52.    /**
  53.    * 创建一个随机字符串,其长度介于包含最小值和最大最大值之间,字符将从拉丁字母(a-z、A-Z)和数字0-9中选择。
  54.    * minLengthInclusive :要生成的字符串的包含最小长度
  55.   * maxLengthExclusive :要生成的字符串的包含最大长度
  56.   */
  57.   random = RandomStringUtils.randomAlphanumeric(5, 68);
  58.   /**
  59.   * 创建一个随机字符串,其长度是指定的字符数,字符将从ASCII值介于32到126之间的字符集中选择(包括)
  60.   * count:随机字符串的长度
  61.   */
  62.   random = RandomStringUtils.randomAscii(15);
  63.   /**
  64.   * 创建一个随机字符串,其长度介于包含最小值和最大最大值之间,字符将从ASCII值介于32到126之间的字符集中选择(包括)
  65.   * minLengthInclusive :要生成的字符串的包含最小长度
  66.   * maxLengthExclusive :要生成的字符串的包含最大长度
  67.   */
  68.   random = RandomStringUtils.randomAscii(15, 30);
  69.   /**
  70.   * 创建一个随机字符串,其长度是指定的字符数,将从数字字符集中选择字符。
  71.   * count:生成随机数的长度
  72.   */
  73.   random = RandomStringUtils.randomNumeric(15);
  74.   /**
  75.   * 创建一个随机字符串,其长度介于包含最小值和最大最大值之间,将从数字字符集中选择字符.
  76.   * minLengthInclusive, 要生成的字符串的包含最小长度
  77.   * maxLengthExclusive 要生成的字符串的包含最大长度
  78.   */
  79.   random = RandomStringUtils.randomNumeric(15, 20);
  1. //产生5位长度的随机字符串,中文环境下是乱码
  2. RandomStringUtils.random(5);
  3. //使用指定的字符生成5位长度的随机字符串
  4. RandomStringUtils.random(5, new char[]{'a','b','c','d','e','f', '1', '2', '3'});
  5. //生成指定长度的字母和数字的随机组合字符串
  6. RandomStringUtils.randomAlphanumeric(5);
  7. //生成随机数字字符串
  8. RandomStringUtils.randomNumeric(5);
  9. //生成随机[a-z]字符串,包含大小写
  10. RandomStringUtils.randomAlphabetic(5);
  11. //生成从ASCII 32到126组成的随机字符串
  12. RandomStringUtils.randomAscii(4)

使用RandomStringUtils可以选择生成随机字符串,可以是全字母,全数字,自定义生成字符等等…
其最基础的方法:

参数解读:

count:需要生成的随机串位数
letters:只要字母
numbers:只要数字
chars:自定义生成字符数组,如果为null,则为所有字符
start、end:选择字符开始生成的位置——-如果chars为null,start就是ASCII你想开始生成字符的位置,end同理;chars不为空的话,就是你自定义字符数组开始生成字符的位置
random:随机源
1、random(int count) //在所有字符中随机生成6位
2、randomAscii(int count) //在ASCII表中的打印字符中,即ASCII表32-127中随机生成6位
3、randomAlphabetic(int count) // 生成只有字母的随机字符串,但是此方法的效率不高,不建议这样使用
4、randomAlphanumeric(int count) //生成只有字母和数字的随机字符串,同样不建议这样使用
5、randomNumeric(int count) // 生成只有数字的随机字符串,
6、random(int count, boolean letters, boolean numbers) //可以指定是否要限定只生成字母或数字,上述三个方法都是调用此方法
7、random(int count, int start, int end, boolean letters, boolean numbers) //可以指定字符集开始的位置,即不用搜索所有全部字符,同时可指定是否指定是否只生成字母或数字
8、random(int count, int start, int end, boolean letters, boolean numbers, char[] chars) //用指定的字符集生成字符串
9、random(int count, String chars) //使用指定字符串的字符生成新的随机字符串
10、String random(int count, char[] chars) //用指定的字符集生成字符串,只是不能指定letters和numbers,其实还是调用了8