Pregunta Compruebe si solo existe un elemento utilizando guava


Recientemente tuve la necesidad de hacer un escenario de 'caso especial' si solo existe un elemento en la colección. Verificando para ...size() == 1 y recuperar usando ...iterator.next() se veía feo, así que creé dos métodos en la clase Colecciones de cerveza casera:

public class Collections {
    public static <T> boolean isSingleValue(Collection<T> values) {
        return values.size() == 1;
    }

    public static <T> T singleValue(Collection<T> values) {
        Assert.isTrue(isSingleValue(values));
        return values.iterator().next();
    }
}

Hace algunos días descubrí que la guayaba tiene un método llamado Iterables.getOnlyElement. Cubre mi necesidad y reemplaza singleValue, pero no puedo encontrar coincidencias para isSingleValue. ¿Es eso por diseño? ¿Vale la pena solicitar una función para tener Iterables.isOnlyElement ¿método?

EDITAR: Como hubo pocos votos favorables, decidí abrir mejoras en la guayaba número 957. Resolución final - 'WontFix'. Los argumentos son muy similares a lo que Thomas / Xaerxess proporcionó.


5
2018-04-03 06:29


origen


Respuestas:


Bueno, no ganarías mucho reemplazando values.size() == 1 con un método, excepto que podría verificar nulo. Sin embargo, hay métodos en Apache Commons Collections (así como en Guava, supongo) para hacer eso.

Prefiero escribir if( values.size() == 1 ) o if( SomeHelper.size(values) == 1 ) 
que if( SomeHelper.isSingleValue(values) ) - la intención es mucho más clara en los primeros dos enfoques y es tanto código para escribir como en el tercer enfoque.


10
2018-04-03 06:48



Solo en adición a otras respuestas (iba a escribir algo como @daveb que eliminó la suya): Si no hay exactamente un elemento, entonces Iterables#getOnlyElement arrojará un IllegalArgumentException o NoSuchElementException) - una respuesta a la pregunta de por qué no hay Iterables.isSingleValue(Iterable) en guayaba

Creo que estás haciendo esto mal. Si:

  • La invocación del método no cambia de estado (a diferencia next() en iterador, es por eso hasNext() existe)
  • y puede decir de manera clara y explícita que el valor devuelto no es un caso excepcional (a diferencia de null regresado de Map#get(Object) - puede ser un valor nulo o puede significar que la clave no se encontró en el mapa)

no hay necesidad de verificar el método si la condición es verdadera y luego hacer alguna operación (¡con aserción en ella!) como en su código de muestra.

Si está absolutamente seguro de que el iterable en este lugar no puede tener un tamaño distinto de 1, entonces la verificación de condición es redundante (se arroja una excepción en otros casos).
Si solo quieres obtener el primer elemento en la colección no vacía, collection.iterator.next() está perfectamente bien (NoSuchElementException se lanza si la colección está vacía).
Si no sabe nada sobre el tamaño de la colección que Iterables.getFirst(iterable, default) es para ti.

PD Si tu Collections#isSingleValue usado solo localmente aquí (por lo tanto podría ser privado) que De Verdad significa que no necesita ese cheque antes de llamar Iterables#getOnlyValue.

P.P.S. Otra respuesta a su pregunta sobre el diseño de Guava podría ser el Artículo 57 de Joshua Bloch Java efectivo - hay pocos métodos diferentes de ayuda en Guava que mencioné antes que explícitamente dicen qué es un caso excepcional para cada uno; La verificación booleana no se agregó debido a que el API es lo más pequeño posible.


6
2018-04-03 07:13



En este momento estoy teniendo el mismo problema.

Voy a resolver con este código:

public static <T> void hasJustOne(T... values) {
    hasJustOne(Predicates.notNull(), values);
}

public static <T> void hasJustOne(Predicate<T> predicate, T... values) {
    Collection<T> filtred = Collections2.filter(Arrays.asList(values),predicate);
    Preconditions.checkArgument(filtred.size() == 1);
}

0
2018-02-27 03:21