从性能角度分析一下String,List,Map

使用String.subString()方法的时候注意内存溢出的问题

  public static void testH() {
    List<String> strings = new ArrayList<String>();
    for (int i = 0; i < 1000; i++) {
      HugeStr h = new HugeStr();
      // ImprovedHugeStr h = new ImprovedHugeStr();
      strings.add(h.getSubString(1, 5));
    }
  }

  static class HugeStr {
    private String str = new String(new char[10000]);

    String getSubString(int begin, int end) {
      return str.substring(begin, end);        //会内存溢出
    }
  }

  static class ImprovedHugeStr {
    private String str = new String(new char[10000]);

    String getSubString(int begin, int end) {
      return new String(str.substring(begin, end));    //返回的新String,没有溢出
    }
  }

三种分隔字符串的方法,split()简单性能最差,StringTokenizer性能次之,自定义的方法性能最好但是可读性太低。建议StringTokenizer

  static String initOrgStr() {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < 1000; i++) {
      sb.append(i);
      sb.append(":");
    }
    return sb.toString();
  }

  static void normalSplidTest() {
    String orgStr = initOrgStr();
    for (int i = 0; i < 10000; i++) {
      orgStr.split(";");
    }
  }

  static void stringTokenizerTest() {
    String orgStr = initOrgStr();
    StringTokenizer st = new StringTokenizer(orgStr, ":");
    for (int i = 0; i < 10000; i++) {
      while (st.hasMoreElements()) {
        st.nextElement();

      }
      st = new StringTokenizer(orgStr, ":");
    }
  }

  static void selfSplidTest() {
    String orgStr = initOrgStr();
    String tmp = orgStr;
    for (int i = 0; i < 10000; i++) {
      while (true) {
        String splitStr = null;
        int j = tmp.indexOf(":");
        if (j < 0) {
          break;
        }
        splitStr = tmp.substring(0, j);
        tmp = tmp.substring(j + 1);
      }

      tmp = orgStr;
    }
  }

String的charAt()和jindexOf()性能都特别的好,charAt连用甚至比startWith()、endWith()还快。

StringBuilder和StringBuffer:String在使用 “+”的时候,如果 + 的是具体的字符串,也就是编译期可知的,那么在编译期就已经完成了优化,只有最后的一个大字符串。

String result = "String" + "and" + "String"
// 反编译后只有这一个大字符串
String result = "StringandString"

StringBuilder.append还是会按照代码的顺序执行,依次append。

StringBuilder sb = 呢我StringBuilder()
sb.append("String");
sb.append("and");
sb.append("String");

如果编译期不可知,最终也是用StringBuilder进行优化。

String str1 = "String";
String str2 = "and";
String str3 = "String";
String result = str1 + str2 + str3;
//反编译
String s = (new StringBuilder(String.valueOf(str1))).append(str2).append(str3).toString();

如果超大的字符串,String的 + ,被反编译StringBuilder实现,但是每次都会生成新的 StringBuilder。String的 + 最差,concat次之,StringBuilder最好。

  static void hugeStr() {
    String s = "";
    for (int i = 0; i < 10000; i++) {
      s += i;
    }

    String result = "";
    for (int i = 0; i < 10000; i++) {
      result = result.concat(String.valueOf(i));
    }

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 10000; i++) {
      sb.append(i);
    }
  }

StringBuffer线程安全,StringBuilder线程不安全。如果单线程StringBuilder会比StringBuffer好些。

如果知道字符串会有多大,在初始化的时候给定值,性能会更好。

public StringBuilder(int capacity)
public StringBuffer(int capacity)

ArrayList、Vector:Vector线程安全。其他几乎一样。LinkedList使用双向连表。

如果list对象需要经常在任意位置插入元素,可以考虑使用LinkList代替ArrayList。但是LinkList从中间删除元素会特别耗时,它是遍历所有,找到具体的位置,在移除。
ArrayList和LinkList三种遍历方法。foreach和迭代器两种差不多,for循环LinkedList不要用,慢到你无法想象。迭代器会更好些,foreach最终也会解析成迭代器还多了一步没用的复制语句所以性能差一些。

  static void eachList(List<String> list) {
    String tmp;
    for (String s : list) {
      tmp = s;
    }

    for (Iterator<String> it = list.iterator(); it.hasNext();) {
      tmp = it.next();
    }

    int size = list.size();
    for (int i = 0; i < size; i++) {
      tmp = list.get(i);
    }
  }

Map

HashMap:它最重要的就是原理了。理解原理。
LinkedHashMap:在HashMap的基础上加了一个链表存放顺序。accessOrder为true按照元素最后访问时间顺序,为false按照存入顺序,默认false。

public LinkedHashMap(int initialCapacity, folat loadFactor, boolean accessOrder)

可以修改accessOrder看看顺序

  static void mapTest() {
    LinkedHashMap<Integer, String> map = new LinkedHashMap<>(16, 0.75F, false);
    map.put(3, "k");
    map.put(1, "f");
    map.put(2, "z");
    map.put(7, "z");
    map.put(8, "z");
    map.put(6, "z");
    map.put(4, "z");
    map.put(5, "z");
    map.get(8);
    map.get(7);
    map.get(6);
    for (Iterator<Integer> iterator = map.keySet().iterator(); iterator.hasNext();) {
      Integer key = (Integer) iterator.next();
      System.out.println(key);
    }
  }

TreeMap:这个就nb了,根据key排序。想使用这个或者在 new TreeMap(Comparator<? super K> comparator)创建的时候指定Comparator,或者key实现了Comparable接口。

  static void treeMapTest() {
    Map<Integer, String> map = new TreeMap<>();
    map.put(3, "k");
    map.put(1, "f");
    map.put(2, "z");
    map.put(7, "z");
    map.put(8, "z");
    map.put(6, "z");
    map.put(4, "z");
    map.put(5, "z");
    for (Iterator<Integer> iterator = map.keySet().iterator(); iterator.hasNext();) {
      Integer key = (Integer) iterator.next();
      System.out.println(key);
    }
    
    Map map2 = ((TreeMap) map).subMap(1, 4);
    System.out.println("get the key more than or equal  1 and less than 4");
    for (Iterator<Integer> iterator = map2.keySet().iterator(); iterator.hasNext();) {
      Integer key = (Integer) iterator.next();
      System.out.println(key);
    }
    // 小于2的
    Map map3 = ((TreeMap) map).headMap(2);
    // 大于2的
    Map map4 = ((TreeMap) map).tailMap(2);
  }
原文地址:https://www.cnblogs.com/badboyf/p/6529178.html