Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Jun 30th, 2012  |  syntax: None  |  size: 14.96 KB  |  hits: 11  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. What's the fastest way to concatenate two Strings in Java?
  2. String ccyPair = ccy1 + ccy2;
  3.        
  4. java.lang.StringBuilder.append(StringBuilder.java:119)  
  5. java.lang.StringBuilder.(StringBuilder.java:93)
  6.        
  7. private final String s1 = new String("1234567890");
  8. private final String s2 = new String("1234567890");
  9.        
  10. @Test public void testConcatenation() {
  11.     for (int i = 0; i < COUNT; i++) {
  12.         String s3 = s1 + s2;
  13.     }
  14. }
  15.        
  16. String s3 = s1 + s2;
  17.        
  18. String s3 = new StringBuilder(s1).append(s2).toString();
  19.        
  20. String s3 = new StringBuffer(s1).append(s2).toString();
  21.        
  22. String s3 = s1.concat(s2);
  23.        
  24. String s3 = "1234567890" + "1234567890";
  25.        
  26. public class Pair<T1, T2> {
  27.     private T1 first;
  28.     private T2 second;
  29.  
  30.     public static <U1,U2> Pair<U1,U2> create(U1 first, U2 second) {
  31.         return new Pair<U1,U2>(U1,U2);
  32.     }
  33.  
  34.     public Pair( ) {}
  35.  
  36.     public Pair( T1 first, T2 second ) {
  37.         this.first = first;
  38.         this.second = second;
  39.     }
  40.  
  41.     public T1 getFirst( ) {
  42.         return first;
  43.     }
  44.  
  45.     public void setFirst( T1 first ) {
  46.         this.first = first;
  47.     }
  48.  
  49.     public T2 getSecond( ) {
  50.         return second;
  51.     }
  52.  
  53.     public void setSecond( T2 second ) {
  54.         this.second = second;
  55.     }
  56.  
  57.     @Override
  58.     public String toString( ) {
  59.         return "Pair [first=" + first + ", second=" + second + "]";
  60.     }
  61.  
  62.     @Override
  63.     public int hashCode( ) {
  64.         final int prime = 31;
  65.         int result = 1;
  66.         result = prime * result + ((first == null)?0:first.hashCode());
  67.         result = prime * result + ((second == null)?0:second.hashCode());
  68.         return result;
  69.     }
  70.  
  71.     @Override
  72.     public boolean equals( Object obj ) {
  73.         if ( this == obj )
  74.             return true;
  75.         if ( obj == null )
  76.             return false;
  77.         if ( getClass() != obj.getClass() )
  78.             return false;
  79.         Pair<?, ?> other = (Pair<?, ?>) obj;
  80.         if ( first == null ) {
  81.             if ( other.first != null )
  82.                 return false;
  83.         }
  84.         else if ( !first.equals(other.first) )
  85.             return false;
  86.         if ( second == null ) {
  87.             if ( other.second != null )
  88.                 return false;
  89.         }
  90.         else if ( !second.equals(other.second) )
  91.             return false;
  92.         return true;
  93.     }
  94.  
  95. }
  96.        
  97. int h1 = ccy1.hashCode(), h2 = ccy2.hashCode(), h = h1 ^ h2;
  98.        
  99. StringBuilder ccyPair = new StringBuilder(ccy1)
  100. ccyPair.append(ccy2);
  101.        
  102. StringBuilder ccyPair = new StringBuilder(ccy1.length()+ccy2.length());
  103. ccyPair.append(ccy1);
  104. ccyPair.append(ccy2);
  105.        
  106. public Object get(String key1, String key2) ...
  107.  
  108.     public void put(String key1, String key2, Object value) ...
  109.        
  110. package bestsss.util;
  111.  
  112.  
  113. @SuppressWarnings("unchecked")
  114. public class DoubleKeyMap<K1, K2, V> {
  115.     private static final int MAX_CAPACITY =  1<<29;
  116.  
  117.     private static final Object TOMBSTONE = new String("TOMBSTONE");
  118.  
  119.     Object[] kvs;
  120.     int[] hashes;
  121.     int count = 0;
  122.  
  123.     final int rehashOnProbes;  
  124.  
  125.     public DoubleKeyMap(){
  126.         this(8, 5);
  127.     }
  128.  
  129.     public DoubleKeyMap(int capacity, int rehashOnProbes){
  130.         capacity = nextCapacity(Math.max(2, capacity-1));
  131.         if (rehashOnProbes>capacity){
  132.             throw new IllegalArgumentException("rehashOnProbes too high");
  133.         }
  134.         hashes = new int[capacity];
  135.         kvs = new Object[kvsIndex(capacity)];      
  136.         count = 0;
  137.         this.rehashOnProbes = rehashOnProbes;
  138.     }
  139.  
  140.     private static int nextCapacity(int c) {
  141.         int n = Integer.highestOneBit(c)<<1;
  142.         if (n<0 || n>MAX_CAPACITY){
  143.             throw new Error("map too large");
  144.         }
  145.         return n;
  146.     }
  147.  
  148.     //alternatively this method can become non-static, protected and overriden, the perfoamnce can drop a little
  149.     //but if better spread of the lowest bit is possible, all good and proper
  150.     private static<K1, K2> int hash(K1 key1, K2 key2){
  151.         //spread more, if need be
  152.         int h1 = key1.hashCode();
  153.         int h2 = key2.hashCode();
  154.         return h1+ (h2<<4) + h2; //h1+h2*17
  155.     }
  156.  
  157.     private static int kvsIndex(int baseIdx){
  158.         int idx = baseIdx;  
  159.         idx+=idx<<1;//idx*3
  160.         return idx;
  161.     }
  162.  
  163.     private int baseIdx(int hash){
  164.         return hash & (hashes.length-1);
  165.     }
  166.  
  167.     public V get(K1 key1, K2 key2){
  168.         final int hash = hash(key1, key2);
  169.  
  170.  
  171.         final int[] hashes = this.hashes;
  172.         final Object[] kvs = this.kvs;
  173.         final int mask = hashes.length-1;
  174.  
  175.         for(int base = baseIdx(hash);;base=(base+1)&mask){
  176.             int k = kvsIndex(base);
  177.             K1 k1 = (K1) kvs[k];
  178.             if (k1==null)
  179.                 return null;//null met; no such value
  180.  
  181.             Object value;
  182.             if (hashes[base]!=hash || TOMBSTONE==(value=kvs[k+2]))
  183.                 continue;//next
  184.  
  185.             K2 k2 = (K2) kvs[k+1];
  186.             if ( (key1==k1 || key1.equals(k1)) && (key2==k2 || key2.equals(k2)) ){
  187.                 return (V) value;
  188.             }
  189.         }
  190.     }
  191.     public boolean contains(K1 key1, K2 key2){
  192.         return get(key1, key2)!=null;
  193.     }
  194.  
  195.     public boolean containsValue(final V value){
  196.         final Object[] kvs = this.kvs;
  197.         if (value==null)
  198.             return false;
  199.  
  200.         for(int i=0;i<kvs.length;i+=3){
  201.             Object v = kvs[2];
  202.             if (v==null || v==TOMBSTONE)
  203.                 continue;
  204.             if (value==v || value.equals(v))
  205.                 return true;
  206.         }
  207.         return false;
  208.     }
  209.  
  210.     public V put(K1 key1, K2 key2, V value){
  211.         int hash = hash(key1, key2);
  212.         return doPut(key1, key2, value, hash);
  213.     }
  214.     public V remove(K1 key1, K2 key2){
  215.         int hash = hash(key1, key2);
  216.         return doPut(key1, key2, null, hash);  
  217.     }
  218.  
  219.     //note, instead of remove a TOMBSTONE is used to mark the deletion
  220.     //this may leak keys but deletion doesn't need to shift the array like in Knuth 6.4
  221.     protected V doPut(final K1 key1, final K2 key2, Object value, final int hash){
  222.         //null value -> remove
  223.         int probes = 0;
  224.         final int[] hashes = this.hashes;
  225.         final Object[] kvs = this.kvs;
  226.         final int mask = hashes.length-1;
  227.  
  228.         //conservative resize: when too many probes and the count is greater than the half of the capacity
  229.         for(int base = baseIdx(hash);probes<rehashOnProbes || count<(mask>>1);base=(base+1)&mask, probes++){
  230.             final int k = kvsIndex(base);
  231.             K1 k1 = (K1) kvs[k];
  232.             K2 k2;
  233.             //find a gap, or resize
  234.             Object  old  = kvs[k+2];
  235.             final boolean emptySlot = k1==null || (value!=null && old==TOMBSTONE);
  236.             if (emptySlot || (
  237.                     hashes[base] == hash &&
  238.                     (k1==key1  || k1.equals(key1)) &&
  239.                     ((k2=(K2) kvs[k+1])==key2 || k2.equals(key2)))
  240.             ){
  241.  
  242.                 if (value==null){//remove()
  243.                     if (emptySlot)
  244.                         return null;//not found, and no value ->nothing to do
  245.  
  246.                     value = TOMBSTONE;
  247.                     count-=2;//offset the ++later
  248.                 }
  249.  
  250.                 if (emptySlot){//new entry, update keys
  251.                     hashes[base] = hash;                
  252.                     kvs[k] = key1;
  253.                     kvs[k+1] = key2;
  254.                 }//else -> keys and hash are equal
  255.  
  256.  
  257.                 if (old==TOMBSTONE)
  258.                     old=null;
  259.  
  260.                 kvs[k+2] = value;
  261.                 count++;
  262.  
  263.                 return (V) old;
  264.             }
  265.         }
  266.         resize();
  267.         return doPut(key1, key2, value, hash);//hack w/ recursion, after the resize
  268.     }
  269.  
  270.     //optimized version during resize, doesn't check equals which is the slowest part  
  271.     protected void doPutForResize(K1 key1, K2 key2, V value, final int hash){
  272.         final int[] hashes = this.hashes;
  273.         final Object[] kvs = this.kvs;
  274.         final int mask = hashes.length-1;
  275.  
  276.         //find the 1st gap and insert there
  277.         for(int base = baseIdx(hash);;base=(base+1)&mask){//it's ensured, no equal keys exist, so skip equals part
  278.             final int k = kvsIndex(base);
  279.             K1 k1 = (K1) kvs[k];
  280.             if (k1!=null)
  281.                 continue;
  282.  
  283.             hashes[base] = hash;                
  284.             kvs[k] = key1;
  285.             kvs[k+1] = key2;
  286.             kvs[k+2] = value;
  287.             return;
  288.         }
  289.     }
  290.  
  291.     //resizes the map by doubling the capacity,
  292.     //the method uses altervative varian of put that doesn't check equality, or probes; just inserts at a gap
  293.     protected void resize(){        
  294.         final int[] hashes = this.hashes;
  295.         final Object[] kvs = this.kvs;
  296.         final int capacity = nextCapacity(hashes.length);
  297.  
  298.         this.hashes = new int[capacity];
  299.         this.kvs = new Object[kvsIndex(capacity)];
  300.  
  301.         for (int i=0;i<hashes.length; i++){
  302.             int k = kvsIndex(i);
  303.             K1 key1 = (K1) kvs[k];
  304.             Object value = kvs[k+2];
  305.             if (key1!=null && TOMBSTONE!=value){
  306.                 K2 key2 = (K2) kvs[k+1];
  307.                 doPutForResize(key1, key2, (V) value, hashes[i]);
  308.             }
  309.         }  
  310.     }
  311.  
  312.     public static void main(String[] args) {
  313.         DoubleKeyMap<String, String, Integer> map = new DoubleKeyMap<String, String, Integer>(4,2);
  314.         map.put("eur/usd", "usd/jpy", 1);
  315.         map.put("eur/usd", "usd/jpy", 2);
  316.  
  317.         map.put("eur/jpy", "usd/jpy", 3);
  318.  
  319.         System.out.println(map.get("eur/jpy", "usd/jpy"));
  320.         System.out.println(map.get("eur/usd", "usd/jpy"));
  321.         System.out.println("======");
  322.  
  323.         map.remove("eur/usd", "usd/jpy");
  324.         System.out.println(map.get("eur/jpy", "usd/jpy"));
  325.         System.out.println(map.get("eur/usd", "usd/jpy"));
  326.         System.out.println("======");
  327.         testResize();
  328.     }
  329.     static void testResize(){
  330.         DoubleKeyMap<String, Integer, Integer> map = new DoubleKeyMap<String, Integer, Integer>(18, 17);
  331.         long s = 0;
  332.         String pref="xxx";
  333.  
  334.         for (int i=0;i<14000;i++){
  335.             map.put(pref+i, i, i);
  336.  
  337.             if ((i&1)==1)
  338.                 map.remove(pref+i, i);
  339.             else
  340.                 s+=i;
  341.         }
  342.         System.out.println("sum: "+s);
  343.         long sum = 0;
  344.  
  345.         for (int i=0;i<14000;i++){
  346.             Integer n = map.get(pref+i, i);
  347.             if (n!=null && n!=i){
  348.                 throw new AssertionError();
  349.             }
  350.             if (n!=null){
  351.                 System.out.println(n);
  352.                 sum+=n;
  353.             }
  354.         }
  355.         System.out.println("1st sum: "+s);
  356.         System.out.println("2nd sum: "+sum);
  357.  
  358.  
  359.     }
  360. }
  361.        
  362. ITERATION_LIMIT1: 1
  363. ITERATION_LIMIT2: 10000000
  364. s1: STRING1-1111111111111111111111
  365. s2: STRING2-2222222222222222222222
  366.  
  367. iteration: 1
  368.                                           null:    1.7 nanos
  369.                                  s1.concat(s2):  106.1 nanos
  370.                                        s1 + s2:  251.7 nanos
  371.    new StringBuilder(s1).append(s2).toString():  246.6 nanos
  372.     new StringBuffer(s1).append(s2).toString():  404.7 nanos
  373.                  String.format("%s%s", s1, s2): 3276.0 nanos
  374.  
  375. Tests complete
  376.        
  377. package net.fosdal.scratch;
  378.  
  379. public class StringConcatenationPerformance {
  380.     private static final int    ITERATION_LIMIT1    = 1;
  381.     private static final int    ITERATION_LIMIT2    = 10000000;
  382.  
  383.     public static void main(String[] args) {
  384.         String s1 = "STRING1-1111111111111111111111";
  385.         String s2 = "STRING2-2222222222222222222222";
  386.         String methodName;
  387.         long startNanos, durationNanos;
  388.         int iteration2;
  389.  
  390.         System.out.println("ITERATION_LIMIT1: " + ITERATION_LIMIT1);
  391.         System.out.println("ITERATION_LIMIT2: " + ITERATION_LIMIT2);
  392.         System.out.println("s1: " + s1);
  393.         System.out.println("s2: " + s2);
  394.         int iteration1 = 0;
  395.         while (iteration1++ < ITERATION_LIMIT1) {
  396.             System.out.println();
  397.             System.out.println("iteration: " + iteration1);
  398.  
  399.             // method #0
  400.             methodName = "null";
  401.             iteration2 = 0;
  402.             startNanos = System.nanoTime();
  403.             while (iteration2++ < ITERATION_LIMIT2) {
  404.                 method0(s1, s2);
  405.             }
  406.             durationNanos = System.nanoTime() - startNanos;
  407.             System.out.println(String.format("%50s: %6.1f nanos", methodName, ((double) durationNanos) / ITERATION_LIMIT2));
  408.  
  409.             // method #1
  410.             methodName = "s1.concat(s2)";
  411.             iteration2 = 0;
  412.             startNanos = System.nanoTime();
  413.             while (iteration2++ < ITERATION_LIMIT2) {
  414.                 method1(s1, s2);
  415.             }
  416.             durationNanos = System.nanoTime() - startNanos;
  417.             System.out.println(String.format("%50s: %6.1f nanos", methodName, ((double) durationNanos) / ITERATION_LIMIT2));
  418.  
  419.             // method #2
  420.             iteration2 = 0;
  421.             startNanos = System.nanoTime();
  422.             methodName = "s1 + s2";
  423.             while (iteration2++ < ITERATION_LIMIT2) {
  424.                 method2(s1, s2);
  425.             }
  426.             durationNanos = System.nanoTime() - startNanos;
  427.             System.out.println(String.format("%50s: %6.1f nanos", methodName, ((double) durationNanos) / ITERATION_LIMIT2));
  428.  
  429.             // method #3
  430.             iteration2 = 0;
  431.             startNanos = System.nanoTime();
  432.             methodName = "new StringBuilder(s1).append(s2).toString()";
  433.             while (iteration2++ < ITERATION_LIMIT2) {
  434.                 method3(s1, s2);
  435.             }
  436.             durationNanos = System.nanoTime() - startNanos;
  437.             System.out.println(String.format("%50s: %6.1f nanos", methodName, ((double) durationNanos) / ITERATION_LIMIT2));
  438.  
  439.             // method #4
  440.             iteration2 = 0;
  441.             startNanos = System.nanoTime();
  442.             methodName = "new StringBuffer(s1).append(s2).toString()";
  443.             while (iteration2++ < ITERATION_LIMIT2) {
  444.                 method4(s1, s2);
  445.             }
  446.             durationNanos = System.nanoTime() - startNanos;
  447.             System.out.println(String.format("%50s: %6.1f nanos", methodName, ((double) durationNanos) / ITERATION_LIMIT2));
  448.  
  449.             // method #5
  450.             iteration2 = 0;
  451.             startNanos = System.nanoTime();
  452.             methodName = "String.format("%s%s", s1, s2)";
  453.             while (iteration2++ < ITERATION_LIMIT2) {
  454.                 method5(s1, s2);
  455.             }
  456.             durationNanos = System.nanoTime() - startNanos;
  457.             System.out.println(String.format("%50s: %6.1f nanos", methodName, ((double) durationNanos) / ITERATION_LIMIT2));
  458.  
  459.         }
  460.         System.out.println();
  461.         System.out.println("Tests complete");
  462.  
  463.     }
  464.  
  465.     public static String method0(String s1, String s2) {
  466.         return "";
  467.     }
  468.  
  469.     public static String method1(String s1, String s2) {
  470.         return s1.concat(s2);
  471.     }
  472.  
  473.     public static String method2(String s1, String s2) {
  474.         return s1 + s2;
  475.     }
  476.  
  477.     public static String method3(String s1, String s2) {
  478.         return new StringBuilder(s1).append(s2).toString();
  479.     }
  480.  
  481.     public static String method4(String s1, String s2) {
  482.         return new StringBuffer(s1).append(s2).toString();
  483.     }
  484.  
  485.     public static String method5(String s1, String s2) {
  486.         return String.format("%s%s", s1, s2);
  487.     }
  488.  
  489. }