java methods - ¿Cómo inicializar los valores de HashSet por construcción?




remove declarar (19)

Con Java 9 puedes hacer lo siguiente:

Set.of("a", "b");

y obtendrás un conjunto inmutable que contiene los elementos. Para más detalles vea la documentación de Oracle del conjunto de interfaces .

Necesito crear un Set con valores iniciales.

Set<String> h = new HashSet<String>();
h.add("a");
h.add("b");

¿Hay una manera de hacer esto en una línea de código? Por ejemplo, es útil para un campo estático final.


El patrón Builder podría ser de utilidad aquí. Hoy tuve el mismo problema. donde necesitaba Configurar operaciones de mutación para que me devolviera una referencia del objeto Conjunto, de modo que pueda pasarlo al constructor de súper clase para que también puedan continuar agregando al mismo conjunto construyendo un nuevo StringSetBuilder fuera del Conjunto que la clase secundaria acaba de construir. La clase de constructor que escribí se parece a esto (en mi caso es una clase interna estática de una clase externa, pero también puede ser su propia clase independiente):

public interface Builder<T> {
    T build();
}

static class StringSetBuilder implements Builder<Set<String>> {
    private final Set<String> set = new HashSet<>();

    StringSetBuilder add(String pStr) {
        set.add(pStr);
        return this;
    }

    StringSetBuilder addAll(Set<String> pSet) {
        set.addAll(pSet);
        return this;
    }

    @Override
    public Set<String> build() {
        return set;
    }
}

Observe los métodos addAll() y add() , que son las contrapartes establecidas por Set.add() y Set.addAll() . Finalmente, observe el método build() , que devuelve una referencia al conjunto que encierra el constructor. A continuación se ilustra cómo usar este constructor de conjuntos:

class SomeChildClass extends ParentClass {
    public SomeChildClass(String pStr) {
        super(new StringSetBuilder().add(pStr).build());
    }
}

class ParentClass {
    public ParentClass(Set<String> pSet) {
        super(new StringSetBuilder().addAll(pSet).add("my own str").build());
    }
}

(fea) Inicialización de doble refuerzo sin efectos secundarios:

Set<String> a = new HashSet<>(new HashSet<String>() {{
    add("1");
    add("2");
}})

Pero en algunos casos, si mencionamos que es un buen olor para hacer inmutables las colecciones finales, podría ser realmente útil:

final Set<String> a = Collections.unmodifiableSet(new HashSet<String>(){{
    add("1");
    add("2");
}})

Hay una taquigrafía que utilizo que no es muy eficiente en el tiempo, pero se ajusta a una sola línea:

Set<String> h = new HashSet<>(Arrays.asList("a", "b"));

Nuevamente, esto no es eficiente en el tiempo ya que está construyendo una matriz, convirtiéndose en una lista y utilizando esa lista para crear un conjunto.

Al inicializar conjuntos finales estáticos, normalmente lo escribo así:

public static final String[] SET_VALUES = new String[] { "a", "b" };
public static final Set<String> MY_SET = new HashSet<>(Arrays.asList(SET_VALUES));

Un poco menos feo y la eficiencia no importa para la inicialización estática.


Una de las formas más convenientes es el uso del método genérico Collections.addAll() , que toma una colección y varargs:

Set<String> h = new HashSet<String>();
Collections.addAll(h, "a", "b");

Un poco complicado pero funciona desde Java 5:

Set<String> h = new HashSet<String>(Arrays.asList(new String[] {  
    "a", "b"
}))

Use un método auxiliar para hacerlo legible:

Set<String> h = asSet ("a", "b");

public Set<String> asSet(String... values) {
    return new HashSet<String>(java.util.Arrays.asList(values));
}

Siento que lo más legible es simplemente usar google Guava:

Set<String> StringSet = Sets.newSet("a", "b", "c");

Si solo tiene un valor inicial en conjunto, esto sería suficiente:

Set<String> h = Collections.singleton("a");

Con Eclipse Collections, hay varias maneras diferentes de inicializar un Set contiene los caracteres 'a' y 'b' en una declaración. Eclipse Collections tiene contenedores para objetos y tipos primitivos, así que CharSet cómo podría usar un Set<String> o CharSet además de las versiones mutables, inmutables, sincronizadas y no modificables de ambos.

Set<String> set =
    Sets.mutable.with("a", "b");
HashSet<String> hashSet =
    Sets.mutable.with("a", "b").asLazy().into(new HashSet<String>());
Set<String> synchronizedSet =
    Sets.mutable.with("a", "b").asSynchronized();
Set<String> unmodifiableSet =
    Sets.mutable.with("a", "b").asUnmodifiable();

MutableSet<String> mutableSet =
    Sets.mutable.with("a", "b");
MutableSet<String> synchronizedMutableSet =
    Sets.mutable.with("a", "b").asSynchronized();
MutableSet<String> unmodifiableMutableSet =
    Sets.mutable.with("a", "b").asUnmodifiable();

ImmutableSet<String> immutableSet =
    Sets.immutable.with("a", "b");
ImmutableSet<String> immutableSet2 =
    Sets.mutable.with("a", "b").toImmutable();

CharSet charSet =
    CharSets.mutable.with('a', 'b');
CharSet synchronizedCharSet =
    CharSets.mutable.with('a', 'b').asSynchronized();
CharSet unmodifiableCharSet =
    CharSets.mutable.with('a', 'b').asUnmodifiable();
MutableCharSet mutableCharSet =
    CharSets.mutable.with('a', 'b');
ImmutableCharSet immutableCharSet =
    CharSets.immutable.with('a', 'b');
ImmutableCharSet immutableCharSet2 =
    CharSets.mutable.with('a', 'b').toImmutable();

Eclipse Collections es compatible con Java 5 - 8.

Nota: Soy un comendador de Eclipse Collections.


En Java 8 yo usaría:

Set<String> set = Stream.of("a", "b").collect(Collectors.toSet());

Esto le da un Set mutable preinicializado con "a" y "b". Tenga en cuenta que mientras en JDK 8 esto devuelve un HashSet , la especificación no lo garantiza, y esto podría cambiar en el futuro. Si desea específicamente un HashSet , haga esto en su lugar:

Set<String> set = Stream.of("a", "b")
                        .collect(Collectors.toCollection(HashSet::new));

Puede usar bloque estático para la inicialización:

private static Set<Integer> codes1=
        new HashSet<Integer>(Arrays.asList(1, 2, 3, 4));

private static Set<Integer> codes2 =
        new HashSet<Integer>(Arrays.asList(5, 6, 7, 8));

private static Set<Integer> h = new HashSet<Integer>();

static{
    h.add(codes1);
    h.add(codes2);
}

Puedes hacerlo en Java 6:

Set<String> h = new HashSet<String>(Arrays.asList("a", "b", "c"));

¿Pero por qué? No encuentro que sea más legible que agregar elementos explícitamente.


Usando Java 8 podemos crear HashSet como:

Stream.of("A", "B", "C", "D").collect(Collectors.toCollection(HashSet::new));

Y si queremos un conjunto no modificable podemos crear un método de utilidad como:

public static <T, A extends Set<T>> Collector<T, A, Set<T>> toImmutableSet(Supplier<A> supplier) {
        return Collector.of(
                supplier,
                Set::add, (left, right) -> {
                    left.addAll(right);
                    return left;
                }, Collections::unmodifiableSet);
    }

Este método puede ser utilizado como:

 Stream.of("A", "B", "C", "D").collect(toImmutableSet(HashSet::new));

Esta es una solución elegante:

public static final <T> Set<T> makeSet(@SuppressWarnings("unchecked") T... o) {
        return new HashSet<T>() {
            private static final long serialVersionUID = -3634958843858172518L;
            {
                for (T x : o)
                   add(x);
            }
        };
}

Usando Java 10 (Conjuntos no modificables)

Set<String> strSet1 = Stream.of("A", "B", "C", "D")
         .collect(Collectors.toUnmodifiableSet());

En este caso, el recopilador devolvería el conjunto no modificable introducido en Java 9 como se desprende del set -> (Set<T>)Set.of(set.toArray()) instrucciones set -> (Set<T>)Set.of(set.toArray()) en el código fuente.

Usando Java 9 (Conjuntos no modificables)

Set<String> strSet6 = Set.of("Apple", "Ball", "Cat", "Dog");

Usando Java 8 (Conjuntos modificables)

Usando Stream en Java 8.

Set<String> strSet1 = Stream.of("A", "B", "C", "D")
         .collect(Collectors.toCollection(HashSet::new));

// stream from an array (String[] stringArray)
Set<String> strSet2 = Arrays.stream(stringArray)
         .collect(Collectors.toCollection(HashSet::new));

// stream from a list (List<String> stringList)
Set<String> strSet3 = stringList.stream()
         .collect(Collectors.toCollection(HashSet::new));

Usando Java 8 (Conjuntos no modificables)

Usando Collections.unmodifiableSet - Podemos usar Collections.unmodifiableSet como:

Set<String> strSet4 = Collections.unmodifiableSet(strSet1);

Pero parece un poco incómodo y podemos escribir nuestro propio coleccionista así:

class ImmutableCollector {
    public static <T> Collector<T, Set<T>, Set<T>> toImmutableSet() {
        return Collector.of(HashSet::new, Set::add, (l, r) -> {
            l.addAll(r);
            return l;
        }, Collections::unmodifiablSet);
    }
}

Y luego usarlo como:

Set<String> strSet4 = Stream.of("A", "B", "C", "D")
             .collect(ImmutableCollector.toImmutableSet());

Usando Collectors.collectingAndThen - Otro enfoque es usar el método Collectors.collectingAndThen que nos permite realizar transformaciones de acabado adicionales:

import static java.util.stream.Collectors.*;
Set<String> strSet5 = Stream.of("A", "B", "C", "D").collect(collectingAndThen(
   toCollection(HashSet::new),Collections::unmodifiableSet));

Si solo nos preocupamos por Set , también podemos usar Collectors.toSet() en lugar de Collectors.toCollection(HashSet::new) .

Un punto a tener en cuenta es que el método Collections::unmodifiableSet devuelve una vista no modificable del conjunto especificado, según doc . Una colección de vista no modificable es una colección que no se puede modificar y también es una vista de una colección de respaldo. Tenga en cuenta que los cambios en la colección de respaldo podrían seguir siendo posibles, y si se producen, son visibles a través de la vista no modificable. Pero el método Collectors.unmodifiableSet devuelve un conjunto realmente inmutable en Java 10 .


Si el tipo contenido del Conjunto es una enumeración, entonces hay un método de fábrica construido en Java (desde la versión 1.5):

Set<MY_ENUM> MY_SET = EnumSet.of( MY_ENUM.value1, MY_ENUM.value2, ... );

Solo una pequeña nota, independientemente de cuál de los enfoques finos mencionados aquí termine, si esta es una opción predeterminada que generalmente no se modifica (como la configuración predeterminada en una biblioteca que está creando), es una buena idea seguir este patrón. :

// Initialize default values with the method you prefer, even in a static block
// It's a good idea to make sure these defaults aren't modifiable
private final static Set<String> DEFAULT_VALUES = Collections.unmodifiableSet(...);
private Set<String> values = DEFAULT_VALUES;

El beneficio depende de la cantidad de instancias que cree de esa clase y de la probabilidad de que se cambien los valores predeterminados.

Si decide seguir este patrón, también puede elegir el método de inicialización de conjuntos que sea más fácil de leer. Como las diferencias micro en la eficiencia entre los diferentes métodos probablemente no importarán mucho, ya que iniciará el conjunto solo una vez.


import com.google.common.collect.Sets;
Sets.newHashSet("a", "b");

o

import com.google.common.collect.ImmutableSet;
ImmutableSet.of("a", "b");

En Java, no puedes hacer

ArrayList<String> places = new ArrayList<String>( Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));

Como se señaló, tendría que hacer una inicialización de doble refuerzo:

List<String> places = new ArrayList<String>() {{ add("x"); add("y"); }};

Pero esto puede forzarle a agregar una anotación @SuppressWarnings("serial") o generar un UUID en serie que es molesto. Además, la mayoría de los formateadores de código lo desempaquetarán en varias declaraciones / líneas.

Alternativamente puedes hacer

List<String> places = Arrays.asList(new String[] {"x", "y" });

pero entonces es posible que desee hacer un @SuppressWarnings("unchecked") .

También de acuerdo con javadoc deberías poder hacer esto:

List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");

Pero no puedo compilarlo con JDK 1.6.





java collections constructor initialization hashset