Vector o ArrayList

Clase Vector o Clase ArrayList
¿Qué es mejor usar en Java? ¿Un Vector o un ArrayList?

  • Sincronización: La clase Vector es sincronizada (synchronized), por tanto, su contenido está protegido de otros hilos, es decir, es thread-safe(Wiki).

Y al contrario, los ArrayList no son sincronizados y por tanto no son thread-safe. Hay que tener en cuanta esto porque los vectores tienen un coste en tiempo de ejecución que no tienen los ArrayList. Si no necesitas thead-safe, usa ArrayList.

  • Tamaño de los datos:Ambas estructuras necesitan un Array para almacenar los datos internamente. Cuando se insertan datos, tanto unos como otros tienen que crecer para que no haya un desbordamiento. He aquí la diferencia:
    Los vectores crecen duplicando su espacio
    Los ArrayList crecen añadiendo el 50% de su espacio anterior.

:)

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Habria que mencionar que a

Habria que mencionar que a Vector se le puede asignar una capacidad de incremento deseada :) , como:
new Vector(capacidad_inicial, incremento);

no siempre duplican su espacio :P , buen blog soulpower n.n , felicidades

=)

Saludos

Hola me parece muy interesante, pero podrías ser más especifico?...podrías demostrar lo que dices por favor :D no se tal vez con alguna prueba de profiling o midiendo la cantidad de memoria en heap que ocupen cada una de la estructuras antes descritas. Te lo agradeceríamos enormemente. Saludos

Imagen de ezamudio

Ejemplo

Corran este programita y vean los resultados en su propia compu. Van a variar incluso de una corrida a otra, pero consistentemente será bastante menor el tiempo que tarda el ArrayList en agregar 10mil elementos.

import java.util.Vector;
import java.util.ArrayList;

public class PruebaListas {

public static void main(String[] args) {
  long t0, t1, t2;
  Vector v = new Vector(10000, 50);
  ArrayList a = new ArrayList(10000);
  v.add(new Integer(0));
  a.add(new Integer(0));
  //Ahora agreguemos 10000 elementos al vector
  t0 = System.currentTimeMillis();
  for (int i = 0; i < 10000; i++) {
    v.add(Integer.toString(i));
  }
  t1 = System.currentTimeMillis();
  long tv = t1-t0;
  //Y luego 10000 elementos al arraylist
  t0 = System.currentTimeMillis();
  for (int i = 0; i < 10000; i++) {
    a.add(Integer.toString(i));
  }
  t1 = System.currentTimeMillis();
  long ta = t1-t0;
  System.out.printf("10K elementos en Vector tarda %d%n", tv);
  System.out.printf("10K elementos en ArrayList tarda %d%n", ta);
}

}

Yo creo que es ligeramente

Yo creo que es ligeramente menor el tiempo en ArrayList por que Vector es sincronizada.

Para definir el incremento

Para definir el incremento en un Vector se puede usar el contructor public Vector(int initialCapacity, int capacityIncrement)

Imagen de ezamudio

Velocidad

Sí, el punto era demostrar que ArrayList es más rápido porque no es sincronizado. Eso se menciona en el post original y es lo que un comentario posterior pedía demostración. Y el constructor que usé en el ejemplo para Vector, usa el parámetro de incremento en la capacidad del mismo.

Imagen de camiloleal

ArrayList

ArrayList

Imagen de arterzatij

despues de poco mas de 8 años

Hoy me encontré con este hilo y quería hacer un ejercicio de pruebas parametrizadas con jUnit así que tome esta discusión como pretexto y el código del buen @ezamudio para mi ejercicio con un par de peques modificaciones.

Tome t0 desde antes de la construcción para no solo tomar en cuenta la inserción y las colecciones toma enteros no cadenas.

Realice los siguientes jUnits:

VectorTest
  1.   /**
  2.  *
  3.  */
  4. package test;
  5.  
  6. import java.util.Arrays;
  7. import java.util.Collection;
  8. import java.util.Vector;
  9.  
  10. import org.junit.After;
  11. import org.junit.Test;
  12. import org.junit.runner.RunWith;
  13. import org.junit.runners.Parameterized;
  14. import org.junit.runners.Parameterized.Parameters;
  15.  
  16. /**
  17.  * @author earteaga
  18.  *
  19.  */
  20. @RunWith(Parameterized.class)
  21. public class VectorTest {
  22.  
  23.   @Parameters
  24.   public static Collection<Object[]> data() {
  25.  
  26.     return Arrays.asList(
  27.         new Object[][] {
  28.             { 10, 10 },
  29.             { 10, 100 },
  30.             { 10, 1000 },
  31.             { 100, 10 },
  32.             { 100, 100 },
  33.             { 100, 1000 },
  34.             { 1000, 10 },
  35.             { 1000, 100 },
  36.             { 1000, 1000 },
  37.             { 10000, 10 },
  38.             { 10000, 100 },
  39.             { 10000, 1000 },
  40.             { 100000, 10 },
  41.             { 100000, 100 },
  42.             { 100000, 1000 },
  43.             { 1000000, 10 },
  44.             { 1000000, 100 },
  45.             { 1000000, 1000 }
  46.         });
  47.   }
  48.  
  49.   @Test
  50.   public void test() {
  51.     long t = 0;
  52.    
  53.     for(int j = 0; j < testCicles; j++) {
  54.       t0 = System.currentTimeMillis();
  55.       vector = new Vector<Integer>(dataQTY, (int) (dataQTY * INC_RATE));
  56.  
  57.       for(int i = 0; i < dataQTY; i++) {
  58.         vector.add(i);
  59.       }
  60.      
  61.       vector.clear();
  62.      
  63.       t = System.currentTimeMillis() - t0;
  64.       tt += t;
  65.       //System.out.printf("%d elementos en ArrayList tarda %d%n", dataQTY, t);
  66.     }
  67.   }
  68.  
  69.   /**
  70.    * @throws java.lang.Exception
  71.    */
  72.   @After
  73.   public void tearDown() throws Exception {
  74.     vector = null;
  75.     System.out
  76.         .printf(
  77.             "%d ciclos de insercion de %d elementos en Vector tarda %d, con %d porciento de incremento en la capacidad incial\n",
  78.             testCicles, dataQTY, tt, (int) (INC_RATE * 100));
  79.   }
  80.  
  81.   /**
  82.    * @param dataQTY
  83.    * @param testCicles
  84.    */
  85.   public VectorTest(int dataQTY, int testCicles) {
  86.  
  87.     super();
  88.     this.dataQTY = dataQTY;
  89.     this.testCicles = testCicles;
  90.   }
  91.  
  92.   private int dataQTY;
  93.  
  94.   private int testCicles;
  95.  
  96.   private long t0;
  97.  
  98.   private long tt = 0;
  99.  
  100.   private Vector<Integer> vector;
  101.  
  102.   private static final double INC_RATE = 1.0;
  103. }
ArrayListTest
  1. /**
  2.  *
  3.  */
  4. package test;
  5.  
  6. import java.util.ArrayList;
  7. import java.util.Arrays;
  8. import java.util.Collection;
  9.  
  10. import org.junit.After;
  11. import org.junit.Test;
  12. import org.junit.runner.RunWith;
  13. import org.junit.runners.Parameterized;
  14. import org.junit.runners.Parameterized.Parameters;
  15.  
  16. /**
  17.  * @author earteaga
  18.  *
  19.  */
  20. @RunWith(Parameterized.class)
  21. public class ArrayListTest {
  22.  
  23.   @Parameters
  24.   public static Collection<Object[]> data() {
  25.  
  26.     return Arrays.asList(
  27.         new Object[][] {
  28.             { 10, 10 },
  29.             { 10, 100 },
  30.             { 10, 1000 },
  31.             { 100, 10 },
  32.             { 100, 100 },
  33.             { 100, 1000 },
  34.             { 1000, 10 },
  35.             { 1000, 100 },
  36.             { 1000, 1000 },
  37.             { 10000, 10 },
  38.             { 10000, 100 },
  39.             { 10000, 1000 },
  40.             { 100000, 10 },
  41.             { 100000, 100 },
  42.             { 100000, 1000 },
  43.             { 1000000, 10 },
  44.             { 1000000, 100 },
  45.             { 1000000, 1000 }
  46.         });
  47.   }
  48.  
  49.   @Test
  50.   public void test() {
  51.     long t = 0;
  52.    
  53.     for(int j = 0; j < testCicles; j++) {
  54.       t0 = System.currentTimeMillis();
  55.       arrayList = new ArrayList<Integer>(dataQTY);
  56.  
  57.       for(int i = 0; i < dataQTY; i++) {
  58.         arrayList.add(i);
  59.       }
  60.      
  61.       t = System.currentTimeMillis() - t0;
  62.       tt += t;
  63.       //System.out.printf("%d elementos en ArrayList tarda %d%n", dataQTY, t);
  64.     }    
  65.   }
  66.  
  67.   /**
  68.    * @throws java.lang.Exception
  69.    */
  70.   @After
  71.   public void tearDown() throws Exception {
  72.     arrayList.clear();
  73.     arrayList = null;
  74.     System.out.printf("%d ciclos de insercion de %d elementos en ArrayList tarda %d%n", testCicles, dataQTY, tt);
  75.   }
  76.  
  77.   /**
  78.    * @param dataQTY
  79.    * @param testCicles
  80.    * @param incRate
  81.    */
  82.   public ArrayListTest(int dataQTY, int testCicles) {
  83.  
  84.     super();
  85.     this.dataQTY = dataQTY;
  86.     this.testCicles = testCicles;
  87.   }
  88.  
  89.   private int dataQTY;
  90.  
  91.   private int testCicles;
  92.  
  93.   private long t0;
  94.  
  95.   private long tt = 0;
  96.  
  97.   private ArrayList<Integer> arrayList;
  98. }

Interesante los resultados, llega un punto en que vector tiene mejor desempeño aunque es esporádico.

Vector:

10 ciclos de insercion de 10 elementos en Vector tarda 0, con 100 porciento de incremento en la capacidad incial
100 ciclos de insercion de 10 elementos en Vector tarda 0, con 100 porciento de incremento en la capacidad incial
1000 ciclos de insercion de 10 elementos en Vector tarda 1, con 100 porciento de incremento en la capacidad incial

10 ciclos de insercion de 100 elementos en Vector tarda 0, con 100 porciento de incremento en la capacidad incial
100 ciclos de insercion de 100 elementos en Vector tarda 0, con 100 porciento de incremento en la capacidad incial
1000 ciclos de insercion de 100 elementos en Vector tarda 7, con 100 porciento de incremento en la capacidad incial

10 ciclos de insercion de 1000 elementos en Vector tarda 1, con 100 porciento de incremento en la capacidad incial
100 ciclos de insercion de 1000 elementos en Vector tarda 5, con 100 porciento de incremento en la capacidad incial
1000 ciclos de insercion de 1000 elementos en Vector tarda 38, con 100 porciento de incremento en la capacidad incial

10 ciclos de insercion de 10000 elementos en Vector tarda 4, con 100 porciento de incremento en la capacidad incial
100 ciclos de insercion de 10000 elementos en Vector tarda 38, con 100 porciento de incremento en la capacidad incial
1000 ciclos de insercion de 10000 elementos en Vector tarda 339, con 100 porciento de incremento en la capacidad incial

10 ciclos de insercion de 100000 elementos en Vector tarda 35, con 100 porciento de incremento en la capacidad incial
100 ciclos de insercion de 100000 elementos en Vector tarda 346, con 100 porciento de incremento en la capacidad incial
1000 ciclos de insercion de 100000 elementos en Vector tarda 3038, con 100 porciento de incremento en la capacidad incial

10 ciclos de insercion de 1000000 elementos en Vector tarda 83, con 100 porciento de incremento en la capacidad incial
100 ciclos de insercion de 1000000 elementos en Vector tarda 992, con 100 porciento de incremento en la capacidad incial
1000 ciclos de insercion de 1000000 elementos en Vector tarda 9481, con 100 porciento de incremento en la capacidad incial

ArrayList

10 ciclos de insercion de 10 elementos en ArrayList tarda 0
100 ciclos de insercion de 10 elementos en ArrayList tarda 0
1000 ciclos de insercion de 10 elementos en ArrayList tarda 1

10 ciclos de insercion de 100 elementos en ArrayList tarda 0
100 ciclos de insercion de 100 elementos en ArrayList tarda 0
1000 ciclos de insercion de 100 elementos en ArrayList tarda 6

10 ciclos de insercion de 1000 elementos en ArrayList tarda 0
100 ciclos de insercion de 1000 elementos en ArrayList tarda 5
1000 ciclos de insercion de 1000 elementos en ArrayList tarda 18

10 ciclos de insercion de 10000 elementos en ArrayList tarda 1
100 ciclos de insercion de 10000 elementos en ArrayList tarda 12
1000 ciclos de insercion de 10000 elementos en ArrayList tarda 106

10 ciclos de insercion de 100000 elementos en ArrayList tarda 8
100 ciclos de insercion de 100000 elementos en ArrayList tarda 117
1000 ciclos de insercion de 100000 elementos en ArrayList tarda 941

10 ciclos de insercion de 1000000 elementos en ArrayList tarda 137
100 ciclos de insercion de 1000000 elementos en ArrayList tarda 894
1000 ciclos de insercion de 1000000 elementos en ArrayList tarda 9797

Y bueno ahí pueden jugar con el rate de incremento para comparar otros datos.

Imagen de javatlacati

Y el warming?

Y el Warming? dónde está el Warming?
A veces es bueno correr unos ciclos de calentamiento para obtener resultados más adecuados.
Saludos!

Imagen de arterzatij

Orales no había escuchado de

Orales no había escuchado de eso.

Que es y como se come?

Son de mis primeras pruebas parametrizadas o donde hay ciclos de por medio.

Imagen de javatlacati

Pon a tu peresozo JDK a hacer calentamiento hasta que sude!

No, no estoy hablando de que tu código Java tenga que hacer cardio...

La primera vez que ejecutas tu código corre significativamente más lento que en veces posteriores, a veces puede ser debido a la carga peresoza, a el uso de compiladores hot-spot o simplemente por la inicialización propia. Si tu código se ejecuta varias veces es muy posible que la segunda vez se reutilice el código y los espacios de memoria, y si estás comparando fragmentos de código similares, que el segundo reutilice elementos del primero, así que para realizar una prueba de performance que sea técnicamente aceptable por todos, lo ideal es correr en algunos ciclos las llamadas que vas a usar en tu programa antes de tomarle tiempo a las partes que te interesan, sin importar que tan trivial sea tu código, normalmente obtienes grandes diferencias de tiempo si haces un calentamiento.

Por ejemplo: para comparar el tiempo de la asignación dentro de un ciclo contra el tiempo fuera de un ciclo

int b;
for (int i = 0; i < 10; i++) {
    b = i;
}

vs

for (int i = 0; i < 10; i++) {
    int b = i;
}

Podríamos usar el siguiente código:

public class CycleTest {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        long iterations = 1000000;
        warmUp(iterations);
        System.out.println("Cycle1");
        double individualTime = getAverageTimePerIterationc1(iterations);
        iterations = 1000;
        double totalTime = getTotalTimec1(iterations);

        System.out.println("ns/iteration: " + individualTime);
        System.out.println("Total time for " + iterations + " runs: " + totalTime);

        System.out.println("Cycle2");
        iterations = 1000000;
        double individualTime1 = getAverageTimePerIterationc2(iterations);
        iterations = 1000;
        double totalTime1 = getTotalTimec2(iterations);

        System.out.println("ns/iteration: " + individualTime1);
        System.out.println("Total time for " + iterations + " runs: " + totalTime1);

    }

    public static void warmUp(long iterations) {
        System.out.println("Starting warmup");
        for (int i = 0; i < iterations; i++) {
            runCycles();
            runCycles1();
        }
    }

    public static double getAverageTimePerIterationc1(long iterations) {
        // test
        System.out.println("Starting individual time test");
        long timeTaken = 0;
        for (int i = 0; i < iterations; i++) {
            long startTime = System.nanoTime();
            runCycles();
            timeTaken += System.nanoTime() - startTime;
        }
        return (double) timeTaken / iterations;
    }

    public static long getTotalTimec1(long iterations) {
        // test
        System.out.println("Starting total time test");
        long timeTaken = 0;
        for (int i = 0; i < iterations; i++) {
            long startTime = System.nanoTime();
            runCycles();
            timeTaken += System.nanoTime() - startTime;
        }
        return timeTaken;
    }

    public static double getAverageTimePerIterationc2(long iterations) {
        // test
        System.out.println("Starting individual time test");
        long timeTaken = 0;
        for (int i = 0; i < iterations; i++) {
            long startTime = System.nanoTime();
            runCycles1();
            timeTaken += System.nanoTime() - startTime;
        }
        return (double) timeTaken / iterations;
    }

    public static long getTotalTimec2(long iterations) {
        // test
        System.out.println("Starting total time test");
        long timeTaken = 0;
        for (int i = 0; i < iterations; i++) {
            long startTime = System.nanoTime();
            runCycles1();
            timeTaken += System.nanoTime() - startTime;
        }
        return timeTaken;
    }

    private static void runCycles() {
        double intermediateResult;
        for (int i = 0; i < 1000; i++) {
            intermediateResult = i;
            intermediateResult += 1;
        }
    }

    private static void runCycles1() {
        for (int i = 0; i < 1000; i++) {
            double intermediateResult = i;
            intermediateResult += 1;
        }
    }
}

Este tema es bien interesante, es una lástima que trascienda únicamente a nivel académico como una argucia teórica para optimizar el código.

Tech tlacuilosque
Neh ni mo Javatlacati ;)

Imagen de ezamudio

warmup

cuando haces benchmarks en jvm, debes primero hacer unas rondas de calentamiento. Esto consiste en correr el benchmark varias veces, pero ignorar los resultados. El objetivo es que si las pruebas requieren alojar una cantidad significativa de memoria, lo hagan durante este calentamiento, y también que el JIT se active para que compile todo el código a nativo *antes* de que se hagan las mediciones. Es simple:

for (int i=0; i < 10000; i++) {
  calentamiento();
}
benchmark();

El calentamiento debe ser una versión corta del benchmark, o si el benchmark no es demasiado largo, puede ser el mismo código que se ejecute varias veces.

Cuando vas a hacer mediciones de tiempo, también es muy recomendable que hagas varias mediciones y tomes promedio y varianza, no que hagas solamente una medición. Por ejemplo para la prueba de agregar un millón de elementos, la ejecutas mil veces pero creo que sólo tomas el tiempo total, cuando lo recomendable es que tomes el tiempo de cada vez que la ejecutas y al final saques promedio y varianza. Si la varianza sale alta, puede ser que algo ocurrió con el recolector de basura o con el JIT.

(varianza en este contexto me refiero a la varianza estadística, el cuadrado de la desviación estándar).

Imagen de arterzatij

Gracias por los aportes

Gracias por los aportes

@ezamudio, @javatlacati. De hecho como comentas @javatlacati es precisamente lo que deseo hacer ir integrando este tipo de pruebas en donde me lo permitan y en módulos que considere críticos(falta aprender a discernir esto también), por eso es que estoy aprendiendo lo de pruebas parametrizadas, ya las había manoseado pero no le veía el uso especifico hasta que me tope con este hilo.

Y pues darle la formalidad de estas pruebas desde jUnit y que se ejecuten desde jenkins u otra cosa.

Re: Warm-UP

Duke calentando...

duke

duke

duke

Re: "argucia teórica"

Este tema es bien interesante, es una lástima que trascienda únicamente a nivel académico como una argucia teórica para optimizar el código.

Pues sí. — Por cierto, he aquí un paper: "Statistically Rigorous Java Performance Evaluation" [PDF]. :-P

~~

Imagen de arterzatij

@jpaul gracias por la

@jpaul gracias por la referencia