12. Colección (2)

Resumen del capítulo

  • agregar grupo de elementos
  • colección de impresiones
  • Lista Lista

agregar grupo de elementos

Hay muchos métodos prácticos en las clases Arrays y Collections del paquete java.util , que pueden agregar un conjunto de elementos a una Colección .

Arrays.asList()El método toma una matriz o una lista de elementos separados por comas (usando parámetros variables) y la convierte en un objeto Lista . Collections.addAll()El método acepta un objeto Collection y una matriz o una lista separada por comas, cuyos elementos se agregan a Collection . El siguiente ejemplo muestra estos dos métodos, así como el método más general incluido en todos los tipos de ColecciónaddAll() :

// collections/AddingGroups.java
// Adding groups of elements to Collection objects
import java.util.*;

public class AddingGroups {
    
    
    public static void main(String[] args) {
    
    
        Collection<Integer> collection = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        Integer[] moreInts = {
    
    6, 7, 8, 9, 10};
        collection.addAll(Arrays.asList(moreInts));
        // Runs significantly faster, but you can't
        // construct a Collection this way:
        Collections.addAll(collection, 11, 12, 13, 14, 15);
        Collections.addAll(collection, moreInts);
        // Produces a list "backed by" an array:
        List<Integer> list = Arrays.asList(16, 17, 18, 19, 20);
        list.set(1, 99); // OK -- modify an element
        // list.add(21); // Runtime error; the underlying
        // array cannot be resized.
    }
}

El constructor de la colección puede aceptar otra colección y usarla para inicializarse. Por lo tanto, puede utilizarlo Arrays.asList()para generar entradas para este constructor. Sin embargo, Collections.addAll()se ejecuta más rápido y es fácil crear una colección sin elementos y luego llamarla Collections.addAll(), por lo que esta es la forma preferida.

Collection.addAll()El método solo puede aceptar otra ColecciónArrays.asList() como parámetro, por lo que no tiene Collections.addAll()flexibilidad. Ambos métodos utilizan listas de parámetros variables.

También puede usar directamente Arrays.asList()la salida de como List , pero la implementación subyacente aquí es una matriz y no se puede cambiar su tamaño. Si intenta llamar a o en esta Lista , obtendrá un error de "Operación no admitida" en tiempo de ejecución porque estos dos métodos intentarán modificar el tamaño de la matriz:add()remove()

// collections/AsListInference.java
import java.util.*;

class Snow {
    
    
}

class Powder extends Snow {
    
    
}

class Light extends Powder {
    
    
}

class Heavy extends Powder {
    
    
}

class Crusty extends Snow {
    
    
}

class Slush extends Snow {
    
    
}

public class AsListInference {
    
    
    public static void main(String[] args) {
    
    
        List<Snow> snow1 = Arrays.asList(new Crusty(), new Slush(), new Powder());
        //- snow1.add(new Heavy()); // Exception

        List<Snow> snow2 = Arrays.asList(new Light(), new Heavy());
        //- snow2.add(new Slush()); // Exception

        List<Snow> snow3 = new ArrayList<>();
        Collections.addAll(snow3,new Light(), new Heavy(), new Powder());
        snow3.add(new Crusty());

        // Hint with explicit type argument specification:
        List<Snow> snow4 = Arrays.<Snow>asList(new Light(), new Heavy(), new Slush());
        //- snow4.add(new Powder()); // Exception
    }
}

En Snow4 , preste atención a Arrays.asList()la "pista" en el medio (es decir <Snow>), que le dice al compilador cuál es el tipo de destino real del tipo de Lista deArrays.asList() resultados generado . Esto se denomina especificación de argumento de tipo explícito.

colección de impresiones

debe usarse Arrays.toString()para producir una forma imprimible de la matriz. Pero no se necesita ayuda para imprimir la colección. A continuación se muestra un ejemplo que también presenta colecciones básicas de Java:

// collections/PrintingCollections.java
// Collections print themselves automatically
import java.util.*;

public class PrintingCollections {
    
    
    static Collection fill(Collection<String> collection) {
    
    
        collection.add("rat");
        collection.add("cat");
        collection.add("dog");
        collection.add("dog");
        return collection;
    }

    static Map fill(Map<String, String> map) {
    
    
        map.put("rat", "Fuzzy");
        map.put("cat", "Rags");
        map.put("dog", "Bosco");
        map.put("dog", "Spot");
        return map;
    }

    public static void main(String[] args) {
    
    
        System.out.println(fill(new ArrayList<>()));
        System.out.println(fill(new LinkedList<>()));
        System.out.println(fill(new HashSet<>()));
        System.out.println(fill(new TreeSet<>()));
        System.out.println(fill(new LinkedHashSet<>()));
        System.out.println(fill(new HashMap<>()));
        System.out.println(fill(new TreeMap<>()));
        System.out.println(fill(new LinkedHashMap<>()));
    }
}

Insertar descripción de la imagen aquí

Esto muestra los dos tipos principales en la biblioteca de la colección Java. La diferencia entre ellos es la cantidad de elementos almacenados en cada "espacio" de la colección. El tipo Colección solo puede almacenar un elemento en cada ranura. Dichas colecciones incluyen: Lista , que contiene un conjunto de elementos en un orden específico; Conjunto , donde no se permiten duplicados de elementos; Cola , que solo puede insertar objetos en un extremo del conjunto y eliminar objetos del otro extremo (en este En este caso, esta es solo otra forma de ver la secuencia, por lo que no se muestra). Map almacena dos elementos en cada ranura, a saber, _key_ (clave) y el _value_ (valor) asociado a él.

El comportamiento de impresión predeterminado, utilizando toString()los métodos proporcionados por la colección, puede producir resultados muy legibles. Colección imprime el contenido entre corchetes, con cada elemento separado por comas. El mapa está encerrado entre llaves y cada clave y valor están conectados con un signo igual (clave a la izquierda, valor a la derecha).

El primer fill()método se aplica a todos los tipos de Colección que implementan add()el método para agregar nuevos elementos.

Tanto ArrayList como LinkedList son tipos de List y, como puede ver en el resultado, ambos contienen elementos en orden de inserción. La diferencia entre los dos no está solo en el rendimiento al realizar ciertos tipos de operaciones, sino que LinkedList contiene más operaciones que ArrayList . Estos se analizan con más detalle más adelante en este capítulo.

HashSet , TreeSet y LinkedHashSet son tipos de Set . Como puede ver en el resultado, Set solo contiene uno de cada elemento idéntico, y las diferentes implementaciones de Set almacenan elementos de manera diferente. HashSet utiliza un método bastante complejo para almacenar elementos. Por ahora, solo debes saber que esta técnica es la forma más rápida de recuperar elementos, por lo que el orden de almacenamiento parece no tener sentido (normalmente solo te importa si algo es miembro de un conjunto, y el almacenamiento el orden no carece de importancia). Si el orden de almacenamiento es importante, puede utilizar TreeSet , que ordena los objetos según reglas de comparación; y LinkedHashSet , que ordena los objetos en el orden en que se agregan.

Un mapa (también llamado matriz asociativa) utiliza claves para encontrar objetos, como una simple base de datos. El objeto asociado se llama valor. Supongamos que tiene un mapa que asocia los nombres de los estados de EE. UU. con sus capitales. Si desea la capital de Ohio, puede buscarla usando "Ohio" como clave, casi como si usara un subíndice de matriz. Debido a este comportamiento, Map solo se almacena una vez para cada clave.

Map.put(key, value)Agregue el valor deseado y asócielo con una clave (utilizada para buscar el valor). Map.get(key)Genera el valor asociado a esta clave. El ejemplo anterior solo agrega pares clave-valor y no realiza una búsqueda. Esto se mostrará más adelante.

Tenga en cuenta que el tamaño del mapa no se especifica (ni se considera) aquí, ya que su tamaño cambiará automáticamente. Además, Map también sabe cómo imprimirse, lo que mostrará la clave y el valor asociados.

Este ejemplo utiliza tres tipos básicos de Map : HashMap , TreeMap y LinkedHashMap .

El orden en que se almacenan las claves y los valores en HashMap no es el orden de inserción porque la implementación de HashMap utiliza un algoritmo muy rápido para controlar el orden. TreeMap ordena todas las claves según las reglas de comparación y LinkedHashMap las ordena según el orden de inserción de las claves manteniendo la velocidad de búsqueda de HashMap .

Lista Lista

La lista promete mantener los elementos en una secuencia específica. La interfaz List agrega muchos métodos sobre la base de Collection , lo que permite insertar y eliminar elementos en el medio de List .

Hay dos tipos de Lista :

  • El ArrayList básico , bueno para el acceso aleatorio a elementos, pero más lento al insertar y eliminar elementos en el medio de List .
  • LinkedList , que proporciona acceso secuencial optimizado a través de operaciones de inserción y eliminación de bajo costo en el medio de la Lista . LinkedList es relativamente lento para el acceso aleatorio, pero tiene un conjunto de funciones más amplio que ArrayList .

El siguiente ejemplo importa typeinfo.pets , que se adelanta a la biblioteca de clases del capítulo TypeInfo. Esta biblioteca de clases contiene la jerarquía de clases Pet y algunas clases de utilidad para generar objetos Pet aleatoriamente . No es necesario que conozcas todos los detalles en este momento, sólo dos cosas:

  1. Hay una clase Pet y varios subtipos de Pet .
  2. El método estático devuelve una ArrayListnew PetCreator().list() poblada con objetos Pet seleccionados aleatoriamente :

ListaFeatures.java

import java.util.*;

public class ListFeatures {
    
    
    public static void main(String[] args) {
    
    
        Random rand = new Random(47);
        List<Pet> pets = new PetCreator().list(7);
        System.out.println("1: " + pets);
        Hamster h = new Hamster();
        pets.add(h); // Automatically resizes
        System.out.println("2: " + pets);
        System.out.println("3: " + pets.contains(h));
        pets.remove(h); // Remove by object
        Pet p = pets.get(2);
        System.out.println("4: " + p + " " + pets.indexOf(p));
        Pet cymric = new Cymric();
        System.out.println("5: " + pets.indexOf(cymric));
        System.out.println("6: " + pets.remove(cymric));
        // Must be the exact object:
        System.out.println("7: " + pets.remove(p));
        System.out.println("8: " + pets);
        pets.add(3, new Mouse()); // Insert at an index
        System.out.println("9: " + pets);
        List<Pet> sub = pets.subList(1, 4);
        System.out.println("subList: " + sub);
        System.out.println("10: " + pets.containsAll(sub));
        Collections.sort(sub); // In-place sort
        System.out.println("sorted subList: " + sub);
        // Order is not important in containsAll():
        System.out.println("11: " + pets.containsAll(sub));
        Collections.shuffle(sub, rand); // Mix it up
        System.out.println("shuffled subList: " + sub);
        System.out.println("12: " + pets.containsAll(sub));
        List<Pet> copy = new ArrayList<>(pets);
        sub = Arrays.asList(pets.get(1), pets.get(4));
        System.out.println("sub: " + sub);
        copy.retainAll(sub);
        System.out.println("13: " + copy);
        copy = new ArrayList<>(pets); // Get a fresh copy
        copy.remove(2); // Remove by index
        System.out.println("14: " + copy);
        copy.removeAll(sub); // Only removes exact objects
        System.out.println("15: " + copy);
        copy.set(1, new Mouse()); // Replace an element
        System.out.println("16: " + copy);
        copy.addAll(2, sub); // Insert a list in the middle
        System.out.println("17: " + copy);
        System.out.println("18: " + pets.isEmpty());
        pets.clear(); // Remove all elements
        System.out.println("19: " + pets);
        System.out.println("20: " + pets.isEmpty());
        pets.addAll(new PetCreator().list(4));
        System.out.println("21: " + pets);
        Object[] o = pets.toArray();
        System.out.println("22: " + o[3]);
        Pet[] pa = pets.toArray(new Pet[0]);
        System.out.println("23: " + pa[3].id());
    }
}

Otras categorías relacionadas:

gato.java

public class Cat extends Pet {
    
    
  public Cat(String name) {
    
     super(name); }
  public Cat() {
    
     super(); }
}

Creador.java

import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public abstract class Creator implements Supplier<Pet> {
    
    
    private Random rand = new Random(47);

    // The different types of Pet to create:
    public abstract List<Class<? extends Pet>> types();

    @Override
    public Pet get() {
    
     // Create one random Pet
        int n = rand.nextInt(types().size());
        try {
    
    
            return types().get(n)
                    .getConstructor().newInstance();
        } catch (InstantiationException |
                 NoSuchMethodException |
                 InvocationTargetException |
                 IllegalAccessException e) {
    
    
            throw new RuntimeException(e);
        }
    }

    public Stream<Pet> stream() {
    
    
        return Stream.generate(this);
    }

    public Pet[] array(int size) {
    
    
        return stream().limit(size).toArray(Pet[]::new);
    }

    public List<Pet> list(int size) {
    
    
        return stream().limit(size).collect(Collectors.toCollection(ArrayList::new));
    }
}

Cymric.java

public class Cymric extends Manx {
    
    
  public Cymric(String name) {
    
     super(name); }
  public Cymric() {
    
     super(); }
}

perro.java

public class Dog extends Pet {
    
    
  public Dog(String name) {
    
     super(name); }
  public Dog() {
    
     super(); }
}

egipcioMau.java

public class EgyptianMau extends Cat {
    
    
  public EgyptianMau(String name) {
    
     super(name); }
  public EgyptianMau() {
    
     super(); }
}

hámster.java

public class Hamster extends Rodent {
    
    
  public Hamster(String name) {
    
     super(name); }
  public Hamster() {
    
     super(); }
}

individuo.java

import java.util.Objects;

public class Individual implements Comparable<Individual> {
    
    
    private static long counter = 0;
    private final long id = counter++;
    private String name;

    public Individual(String name) {
    
    
        this.name = name;
    }

    // 'name' is optional:
    public Individual() {
    
    
    }

    @Override
    public String toString() {
    
    
        return getClass().getSimpleName() +
                (name == null ? "" : " " + name);
    }

    public long id() {
    
    
        return id;
    }

    @Override
    public boolean equals(Object o) {
    
    
        return o instanceof Individual &&
                Objects.equals(id, ((Individual) o).id);
    }

    @Override
    public int hashCode() {
    
    
        return Objects.hash(name, id);
    }

    @Override
    public int compareTo(Individual arg) {
    
    
        // Compare by class name first:
        String first = getClass().getSimpleName();
        String argFirst = arg.getClass().getSimpleName();
        int firstCompare = first.compareTo(argFirst);
        if (firstCompare != 0) {
    
    
            return firstCompare;
        }
        if (name != null && arg.name != null) {
    
    
            int secondCompare = name.compareTo(arg.name);
            if (secondCompare != 0) {
    
    
                return secondCompare;
            }
        }
        return (arg.id < id ? -1 : (arg.id == id ? 0 : 1));
    }
}

manx.java

public class Manx extends Cat {
    
    
  public Manx(String name) {
    
     super(name); }
  public Manx() {
    
     super(); }
}

ratón.java

public class Mouse extends Rodent {
    
    
  public Mouse(String name) {
    
     super(name); }
  public Mouse() {
    
     super(); }
}

Mutt.java

public class Mutt extends Dog {
    
    
  public Mutt(String name) {
    
     super(name); }
  public Mutt() {
    
     super(); }
}

mascota.java

public class Pet extends Individual {
    
    
    public Pet(String name) {
    
    
        super(name);
    }

    public Pet() {
    
    
        super();
    }
}

PetCreator.java

import java.util.*;

public class PetCreator extends Creator {
    
    
    // No try block needed.
    public static final
    List<Class<? extends Pet>> ALL_TYPES = Collections.unmodifiableList(Arrays.asList(
                    Pet.class, Dog.class, Cat.class, Rodent.class,
                    Mutt.class, Pug.class, EgyptianMau.class,
                    Manx.class, Cymric.class, Rat.class,
                    Mouse.class, Hamster.class));
    // Types for random creation:
    private static final
    List<Class<? extends Pet>> TYPES =
            ALL_TYPES.subList(
                    ALL_TYPES.indexOf(Mutt.class),
                    ALL_TYPES.size());

    @Override
    public List<Class<? extends Pet>> types() {
    
    
        return TYPES;
    }

    public static void main(String[] args) {
    
    
        System.out.println(TYPES);
        List<Pet> pets = new PetCreator().list(7);
        System.out.println(pets);
    }
}
/* Output:
[class reflection.pets.Mutt, class reflection.pets.Pug,
class reflection.pets.EgyptianMau, class
reflection.pets.Manx, class reflection.pets.Cymric, class
reflection.pets.Rat, class reflection.pets.Mouse, class
reflection.pets.Hamster]
[Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug]
*/

Pug.java

public class Pug extends Dog {
    
    
  public Pug(String name) {
    
     super(name); }
  public Pug() {
    
     super(); }
}

rata.java

public class Rat extends Rodent {
    
    
  public Rat(String name) {
    
     super(name); }
  public Rat() {
    
     super(); }
}

roedor.java

public class Rodent extends Pet {
    
    
  public Rodent(String name) {
    
     super(name); }
  public Rodent() {
    
     super(); }
}

El contenido impreso es el siguiente:

Insertar descripción de la imagen aquí

Las líneas impresas están numeradas para que el resultado pueda rastrearse hasta el código fuente. La primera línea de salida muestra la Lista de mascotas original . A diferencia de las matrices, las listas pueden agregar o eliminar elementos después de la creación y cambiar su tamaño. Eso es exactamente lo que vale: una secuencia modificable. El resultado de agregar un hámster se puede ver en la línea 2 del resultado . El objeto se agregará al final de la lista.

Puede utilizar contains()el método para determinar si un objeto está en la lista. Si desea eliminar un objeto, puede pasar una referencia al objeto al remove()método. Del mismo modo, si tiene una referencia a un objeto, puede usar el número de índice para encontrar la ubicación del objeto en indexOf()la Lista , como se muestra en la línea 4 del resultado.

El método (un método de la clase raíz Object ) se utiliza para determinar si un elemento pertenece a una Lista , encontrar el índice de un elemento y eliminar elementos de la Lista por referencia. Cada mascota se define como un objeto único, por lo que incluso si ya hay dos Cymrics en la lista , si crea un nuevo objeto Cymric y lo pasa al método, el resultado seguirá siendo -1 (que significa no encontrado), e intente llamar al método para eliminar este objeto devolverá falso . Para otras clases, la definición de puede ser diferente. Por ejemplo, dos cadenas son iguales si su contenido es el mismo . Por lo tanto, para evitar sorpresas, es importante tener en cuenta que el comportamiento de la lista cambia según el comportamiento.equals()indexOf()remove()equals()equals()

Las líneas 7 y 8 del resultado muestran que eliminar un objeto que coincide exactamente con un objeto en la Lista es exitoso.

Se puede insertar un elemento en el medio de List , al igual que la salida en la línea 9 y el código anterior. Pero esto crea un problema: con LinkedList , insertar y eliminar desde el medio de la lista son operaciones baratas (en este caso, excepto para el verdadero acceso aleatorio al medio de la lista), pero con ArrayList, son operaciones costosas. ¿Significa esto que los elementos nunca deben insertarse en medio de un ArrayList y, preferiblemente, deben convertirse a un LinkedList ? No, solo significa que debes ser consciente del problema y si comienzas a hacer muchas inserciones en medio de alguna ArrayList y el programa comienza a ralentizarse, entonces deberías ver cómo tu implementación de List podría ser la culpable ( encontré esto La mejor manera de identificar cuellos de botella es utilizar un generador de perfiles). La optimización es un problema complicado y la mejor estrategia es ignorarlo hasta que descubra que tiene que preocuparse por ello (aunque siempre es una buena idea comprender los problemas).

subList()El método puede crear fácilmente sectores a partir de una lista más grande, y es containsAll()natural que se vuelva verdadero al pasar el resultado del sector al método de la lista más grande original . Tenga en cuenta que el orden no es importante, como puede ver en el resultado de las líneas 11 y 12, llamar a los métodos con nombres intuitivos y en sub no afecta el resultado de . Detrás de escena, la lista resultante es la lista original. Por lo tanto, cualquier cambio en la lista devuelta se reflejará en la lista original y viceversa.Collections.sort()Collections.shuffle()containsAll()subList()

retainAll()El método es en realidad una operación de "establecer intersección", que en este caso conserva todos los elementos que están tanto en copy como en sub . Tenga en cuenta nuevamente que el comportamiento resultante equals()depende del método.

equals()La línea 14 del resultado muestra el resultado de eliminar elementos usando números de índice, lo cual es más intuitivo que eliminar elementos mediante referencias de objetos porque no tiene que preocuparse por el comportamiento al usar índices.

removeAll()Los métodos también se equals()ejecutan en función de métodos. Como sugiere el nombre, eliminará todos los elementos del parámetro List de la Lista .

set()El nombre del método parece inapropiado porque potencialmente entra en conflicto con la clase Set . Usar "reemplazar" podría ser más apropiado aquí, ya que su función es reemplazar el elemento en el índice (el primer parámetro) con el segundo parámetro.

La línea 17 del resultado muestra que para List , hay un addAll()método sobrecargado que inserta una nueva lista en el medio de la lista original, en lugar de simplemente agregarla al final de la lista con el método Collection .addAll()

Las líneas 18-20 del resultado muestran el efecto de isEmpty()los métodos y clear().

Las líneas 22 y 23 del resultado muestran cómo utilizar toArray()el método para convertir cualquier Colección en una matriz. Este es un método sobrecargado y su versión sin parámetros devuelve una matriz de Object , pero si se pasa una matriz del tipo de destino a esta versión sobrecargada, generará una matriz del tipo especificado (suponiendo que pase la verificación de tipo). Si la matriz de argumentos es demasiado pequeña para contener todos los elementos de la Lista (como en este ejemplo), toArray()se crea una nueva matriz con las dimensiones adecuadas. El objeto Pet tiene un id()método que se puede invocar en los objetos de la matriz resultante.

Supongo que te gusta

Origin blog.csdn.net/GXL_1012/article/details/132568129
Recomendado
Clasificación