martes, 22 de mayo de 2012

Colecciones en java

?

COLECCIONES
Las colecciones son una especie de arrays de tamaño dinámico. Para usarlas haremos uso del Java Collections Framework (JCF), el cual contiene un conjunto de clases e interfaces del paquete java.util para gestionar colecciones de objetos.
En Java las principales interfaces que disponemos para trabajar con colecciones son: Collection, Set, List, Queue y Map:
  • Collection<E>: Un grupo de elementos individuales, frecuentemente con alguna regla aplicada a ellos.
  • List<E>: Elementos en una secuencia particular que mantienen un orden y permite duplicados. La lista puede ser recorrida en ambas direcciones con un ListIterator. Hay 3 tipos de constructores:
    1. ArrayList<E>: Su ventaja es que el acceso a un elemento en particular es ínfimo. Su desventaja es que para eliminar un elemento, se ha de mover toda la lista para eliminar ese “hueco”.
    2. Vector<E>: Es igual que ArrayList, pero sincronizado. Es decir, que si usamos varios hilos, no tendremos de qué preocuparnos hasta cierto punto.
    3. LinkedList<E>: En esta, los elementos están conectados con el anterior y el posterior. La ventaja es que es fácil mover/eliminar elementos de la lista, simplemente moviendo/eliminando sus referencias hacia otros elementos. La desventaja es que para usar el elemento N de la lista, debemos realizar N movimientos a través de la lista.
    Veamos un ejemplo de List:
  • Set<E>: No puede haber duplicados. Cada elemento debe ser único, por lo que si existe uno duplicado, no se agrega. Por regla general, cuando se redefine equals(), se debe redefinir hashCode(). Es necesario redefinir hashCode() cuando la clase definida será colocada en un HashSet. Los métodos add(o) y addAll(o) devuelven false si o ya estaba en el conjunto.
  • Queue<E>: Colección ordenada con extracción por el principio e inserción por el principio (LIFO – Last Input, First Output) o por el final (FIFO – First Input, First Output). Se permiten elementos duplicados. No da excepciones cuando la cola está vacía/llena, hay métodos para interrogar, que devuelven null. Los métodos put()/take() se bloquean hasta que hay espacio en la cola/haya elementos.
  • Map<K,V>: Un grupo de pares objeto clave-valor, que no permite duplicados en sus claves. Es quizás el más sencillo, y no utiliza la interfaz Collection. Los principales métodos son: put()get()remove().
    1. HashMap<K,V>: Se basa en una tabla hash, pero no es sincronizado.
    2. HashTable<K,V>: Es sincronizado, aunque que no permite null como clave.
    3. LinkedHashMap<K,V>: Extiende de HashMap y utiliza una lista doblemente enlazada para recorrerla en el orden en que se añadieron. Es ligeramente más rápida a la hora de acceder a los elementos que su superclase, pero más lenta a la hora de añadirlos.
    4. TreeMap<K,V>: Se basa en una implementación de árboles en el que ordena los valores según las claves. Es la clase más lenta.
    Ejemplo de Map:
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import java.util.*;
     
    public class Ejemplo
    {
        public static void main(String args[])
        {
            // Definir un HashMap
            HashMap global = new HashMap();
     
            // Insertar valores "key"-"value" al HashMap
            global.put("Laura", "667895789");
            global.put("Pepe", "645895756");
            global.put("Abelardo", "55895711");
            global.put("Daniel", "667111788");
            global.put("Arturo", "667598623");
     
            // Definir Iterator para extraer o imprimir valores
            for( Iterator it = global.keySet().iterator(); it.hasNext();) {
                String s = (String)it.next();
                String s1 = (String)global.get(s);
                System.out.println("Alumno: "+s + " - " + "Telefono: "+s1);
            }
        }
    }
  • Otros tipos de coleccionessingleton()singletonList()singletonMap(). Devuelven conjunto, lista y mapa inmutables, con un único elemento. Útiles para pasar un elemento a un método que espera una colección.
  • El siguiente código es un ejemplo de Colecciones:
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    import java.util.*;
    public class EjemploColecciones {
     
        public static void main(String[] args) {
     
            Collection<String> col1 = new HashSet<String>();
            Collection<String> col2 = Arrays.asList("valor1", "valor2");
            Collection<String> col3 = Collections.singleton("valor3");
     
            // add() y addAll() devuelven true si cambia la colección.
            // Importa en conjuntos
            if (col1.add("cero"))
                System.out.println ("col1 modificada");
            if (col1.addAll(col2))
                System.out.println ("col1 modificada");
     
            // Copiamos usando un copy constructor
            Collection<String> copia = new ArrayList<String>(col1);
            col1.remove("cero");        // eliminar un elemento
            col1.removeAll(col3);       // eliminar los elementos en e de c
            col1.retainAll(col2);       // elimina de c los que no están en d
            col1.clear();               // eliminar todos
            boolean b = col1.isEmpty(); // b == true
            int s = col1.size();        // s == 0
     
            // Recuperamos en c la copia
            b = col1.addAll(copia);     // b == true
            b = col1.contains("cero");  // b == true
            b = col1.containsAll(col2); // b == true;
     
            // Recorremos col1
            Iterator<String> iterador = col1.iterator();
            while(iterador.hasNext())
                System.out.println(iterador.next());
     
            for(Iterator<String> i = col1.iterator(); i.hasNext();)
                System.out.println(i.next());
     
            // Recorremos de col1
            for(String word : col1) System.out.println(word);
     
            // Las colecciones tienen toString()
            System.out.println(col1);
     
            // Copia en un Array
            Object[] elementos = col1.toArray();
     
            // Obtenemos una copia
            String[] strings = col1.toArray(new String[col1.size()]);
     
            //Sin necesidad de saber el tamñao
            strings = col1.toArray(new String[0]);
        }
    }
    El resultado que produce este código es el siguiente:
    Para poder iterar sobre ellos, es necesario un objeto Iterator como hemos visto en el ejemplo.
    Para compararlos, es necesario un objeto comparable. Para ello, es necesario que nuestra clase implemente a la clasejava.lang.Comparable, y usar el método int compareTo(Object o). El método compareTo() devuelve un entero con las siguientes características:
    • Negativo: Si thisObject < anotherObject
    • Cero: Si thisObject == anotherObject
    • Positivo: Si thisObject > anotherObject
    En este ejemplo comparamos cadenas ignorando mayúsculas y minúsculas, e imprimiendo el resultado por orden alfabético:
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // --- Clase Principal --- /
    import java.util.*;
    public class Principal {
        public static void main(String[] args) {
            TreeSet ts = new TreeSet(new Comparacion ());
            ts.add("Alonso");
            ts.add("alonso");
            ts.add("Conchi");
            ts.add("Emilio");
            ts.add("Gómez");
            ts.add("manuela");
            ts.add("Manuela");
            System.out.println(ts);
        }
    }
     
    // --- Clase Comparacion --- /
    import java.util.*;
    class Comparacion implements Comparator {
        public int compare(Object o1, Object o2) {
            //Compara cadenas ignorando las may/min
            return ((String) o1).compareToIgnoreCase((String) o2);
        }
    }
    El resultado es el siguiente:
    En este ejemplo utilizamos la interface Comparable para comprobar objetos iguales:
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    // --- Clase Principal --- /
    import java.util.*;
     
    public class Principal {
        public static void main(String[] args) {
            TreeSet ts = new TreeSet();
            ts.add(new Persona("Pepe", "Perez"));
            ts.add(new Persona("Pipi", "Perez"));
            ts.add(new Persona("Manolito", "Cascos"));
            ts.add(new Persona("Pipi", "Perez"));
            ts.add(new Persona("Sara", "Alonso"));
     
            System.out.println(ts);
        }
    }
     
    // --- Clase Persona --- /
    import java.util.*;
     
    public class Persona implements Comparable {
        private String Nombre, apellido;
     
        public String Nombre(){
            return Nombre;
        }
     
        public String apellido() {
            return apellido;
        }
     
        public Persona(String Nombre, String apellido) {
            if (Nombre==null || apellido==null)
                throw new NullPointerException();   //Comprobar los nulos
            this.Nombre = Nombre;
            this.apellido = apellido;
        }
     
        public boolean equals(Object o) {
                if (!(o instanceof Persona))
                    return false;
                Persona n = (Persona)o;
                // método equals retorna false si argumento
                // no es del tipo adecuado o es nulo
                return n.Nombre.equals(Nombre) &&
                n.apellido.equals(apellido);
            }
     
        public int hashCode() {
            return 31 * Nombre.hashCode() + apellido.hashCode();
        }   // hashcode tiene en cuenta ambos campos
     
        public String toString() {
            return Nombre + " " + apellido;
        }
     
        public int compareTo(Object o) {
            // arroja ClassCastException si argumento no es del tipo Name
            Persona n = (Persona)o;
            int lastCmp = apellido.compareTo(n.apellido);
            return (lastCmp!=0 ? lastCmp : Nombre.compareTo(n.Nombre));
            // primero comparamos los apellidos y si son iguales los nombres
        }
    }
    Y el resultado:
    TIPOS GENÉRICOS
    Los tipos genéricos permiten forzar la seguridad de los tipos, en tiempo de compilación, en las colecciones (u otras clases y métodos que utilicen tipos parametrizados).
    El problema que resuelven es que si al crear una colección de un tipo determinado, pongamos String, yo meto un elemento de tipo entero, entonces me dará una excepción. Los genéricos ayudaron a crear una comprobación de tipo en listas y mapas en tiempo de compilación, anteriormente esto no era posible. Otra cosa que podemos hacer en con los tipos parametrizados o genéricos es crear nuestras propias clases.
    Veamos el problema y la solución con tipos genéricos:
    Es decir, básicamente es un tipo “inventado” al cual le decimos de qué tipo queremos que nos pase los datos y él internamente, hace los diferentes castings que haya que hacerle a los dieferentes elementos de la colección, siendo los tipos de éstos transparentes para nosotros.
    Las convenciones de declaración utilizan la letra T para tipos y E para elementos de una colección. Se puede utilizar más de un tipo parametrizado en una declaración. Por convención los tipos parametrizados son letras solitarias mayúsculas, sin esta convención sería difícil leer el código y decir la diferencia entre una variable parametrizada y una clase ordinaria o un nombre de una interface.
    • E – Elemento (Usado extensivamente en las colecciones en java)
    • K – Key
    • N – Number
    • T – Type
    • V – Value
    • S, U, V etc. – 2nd, 3rd, 4th types