ejemplo - list object java example
¿Hay alguna clase estándar de Java que implemente Iterable sin implementar Collection? (6)
Aunque no hay ninguna clase que se adapte de inmediato a sus necesidades y sea intuitiva para los lectores de su código de prueba, puede crear fácilmente su propia clase anónima que sea fácil de entender:
static Iterable<Integer> range(final int from, final int to) {
return new Iterable<Integer>() {
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
int current = from;
public boolean hasNext() { return current < to; }
public Integer next() {
if (!hasNext()) { throw new NoSuchElementException(); }
return current++;
}
public void remove() { /*Optional; not implemented.*/ }
};
}
};
}
Esta implementación es anónima y no implementa Collection<Integer>
. Por otro lado, produce una secuencia enumerable de enteros no vacía, que puede controlar por completo.
Tengo un enigma que me ha llevado a reflexionar sobre si existen clases Java estándar que implementen Iterable<T>
sin implementar también Collection<T>
. Estoy implementando una interfaz que me obliga a definir un método que acepte un Iterable<T>
, pero el objeto que estoy usando para respaldar este método requiere una Collection<T>
.
Esto me obliga a hacer un código de sentimientos realmente desordenados que dan algunas advertencias sin marcar cuando se compilan.
public ImmutableMap<Integer, Optional<Site>> loadAll(
Iterable<? extends Integer> keys
) throws Exception {
Collection<Integer> _keys;
if (keys instanceof Collection) {
_keys = (Collection<Integer>) keys;
} else {
_keys = Lists.newArrayList(keys);
}
final List<Site> sitesById = siteDBDao.getSitesById(_keys);
// snip: convert the list to a map
¿Cambiar mi colección resultante para usar la Collection<? extends Integer>
más generada Collection<? extends Integer>
Collection<? extends Integer>
tipo Collection<? extends Integer>
no elimina la advertencia sin marcar para esa línea. Además, no puedo cambiar la firma del método para aceptar una Collection
lugar de un Iterable
porque entonces ya no reemplaza al método super y no será llamado cuando sea necesario.
No parece haber una manera de evitar este problema de conversión o copia: otras preguntas se han formulado aquí y en otros lugares y parece estar profundamente arraigado en los sistemas de borrado de tipos y genéricos de Java. Pero en cambio, pregunto si alguna vez hay clases que puedan implementar Iterable<T>
que no implementen también Collection<T>
? He echado un vistazo a través del Iterable
iterable y, ciertamente, todo lo que espero que pase a mi interfaz será en realidad una colección. Me gustaría usar una clase pre-escrita en el mundo salvaje ya que parece que es mucho más probable que se pase como parámetro y haría que la prueba de la unidad fuera mucho más valiosa.
Estoy seguro de que el bit de conversión o copia que he escrito trabaja con los tipos para los que lo estoy utilizando en mi proyecto debido a algunas pruebas unitarias que estoy escribiendo. Pero me gustaría escribir una prueba de unidad para alguna información que sea iterable, pero no es una recopilación y hasta ahora todo lo que he podido encontrar es implementar una implementación de clase de prueba ficticia.
Para curiosos, el método que estoy implementando es el CacheLoader<K, V>.loadAll(Iterable<? extends K> keys)
y el método de respaldo es un objeto de acceso a datos instanciado por JDBI, que requiere que se use una colección como el tipo de parámetro para la interfaz @BindIn
. Creo que tengo razón al pensar que esto es tangencial a la pregunta, pero en caso de que alguien quiera probar el pensamiento lateral sobre mi problema. Soy consciente de que podría simplemente dividir el proyecto JDBI y volver a escribir la anotación @BindIn
para aceptar un iterable ...
Como se mencionó en la respuesta de @bayou.io , una de estas implementaciones para Iterable
es la nueva clase Path
para el cruce de sistemas de archivos introducida en Java 7.
Si se encuentra en Java 8, Iterable
se ha actualizado con (es decir, se le ha dado un método default
) spliterator()
(preste atención a su Nota de implementación ), que le permite usarlo junto con StreamSupport
:
public static <T> Collection<T> convert(Iterable<T> iterable) {
// using Collectors.toList() for illustration,
// there are other collectors available
return StreamSupport.stream(iterable.spliterator(), false)
.collect(Collectors.toList());
}
Esto conlleva un pequeño gasto, ya que cualquier argumento que ya sea una implementación de Collection
pasa por una operación innecesaria de transmisión y recopilación. Probablemente solo deberías usarlo si el deseo de un enfoque estandarizado de JDK supera el potencial de rendimiento, en comparación con tus métodos de fundición originales o basados en guava, que probablemente sean discutibles ya que ya estás usando el CacheLoader
de Guava.
Para probar esto, considere este fragmento y la salida de muestra:
// Snippet
System.out.println(convert(Paths.get(System.getProperty("java.io.tmpdir"))));
// Sample output on Windows
[Users, MyUserName, AppData, Local, Temp]
Después de leer las excelentes respuestas y los documentos proporcionados, busqué en algunas clases más y encontré lo que parece ser el ganador, tanto en términos de sencillez para el código de prueba como para el título de una pregunta directa. La implementación principal de ArrayList
Java contiene esta gema:
public Iterator<E> iterator() {
return new Itr();
}
Donde Itr
es una clase interna privada con una implementación altamente optimizada y personalizada de Iterator<E>
. Desafortunadamente, Iterator
no implementa Iterable
por sí mismo, por lo que si quiero meterlo en mi método auxiliar para probar la ruta del código que no funciona, tengo que envolverlo en mi propia clase de basura que implementa Iterable
(y no Collection
) y devuelve el Itr
. Esta es una forma práctica de convertir fácilmente una colección en un Iterable sin tener que escribir el código de iteración.
En una nota final, mi versión final del código ni siquiera hace la Lists.newArrayList
, porque Guava''s Lists.newArrayList
hace casi exactamente lo que estaba haciendo con la detección del tipo de tiempo de ejecución en la pregunta.
@GwtCompatible(serializable = true)
public static <E> ArrayList<E> More ...newArrayList(Iterable<? extends E> elements) {
checkNotNull(elements); // for GWT
// Let ArrayList''s sizing logic work, if possible
if (elements instanceof Collection) {
@SuppressWarnings("unchecked")
Collection<? extends E> collection = (Collection<? extends E>) elements;
return new ArrayList<E>(collection);
} else {
return newArrayList(elements.iterator());
}
}
En las API principales, los únicos tipos que son Iterable
pero no de Collection
-
interface java.nio.file.Path
interface java.nio.file.DirectoryStream
interface java.nio.file.SecureDirectoryStream
class java.util.ServiceLoader
class java.sql.SQLException (and subclasses)
Podría decirse que estos son todos los malos diseños.
Kludgy, sí, pero creo que el código
Collection<Integer> _keys;
if (keys instanceof Collection) {
_keys = (Collection<Integer>) keys;
} else {
_keys = Lists.newArrayList(keys);
}
es perfectamente sano La interfaz Collection<T>
extiende Iterable<T>
y no se le permite implementar la misma interfaz con 2 parámetros de tipo diferente, por lo que no hay forma de que una clase pueda implementar Collection<String>
e Iterable<Integer>
, por ejemplo.
La clase Integer
es definitiva, por lo que la diferencia entre Iterable<? extends Integer>
Iterable<? extends Integer>
e Iterable<Integer>
es en gran parte académico.
En conjunto, los últimos 2 párrafos demuestran que si algo es a la vez un Iterable<? extends Integer>
Iterable<? extends Integer>
y una Collection
, debe ser una Collection<Integer>
. Por lo tanto, su código está garantizado para ser seguro. El compilador no puede estar seguro de esto, por lo que puede suprimir la advertencia escribiendo
@SuppressWarnings("unchecked")
por encima de la declaración. También debe incluir un comentario junto a la anotación para explicar por qué el código es seguro.
En cuanto a la pregunta de si hay clases que implementan Iterable
pero no Collection
, como otros han señalado, la respuesta es sí. Sin embargo, creo que lo que realmente estás preguntando es si hay algún punto en tener dos interfaces. Muchos otros han preguntado esto. A menudo, cuando un método tiene un argumento de Collection
(por ejemplo, addAll()
podría, y probablemente debería, ser un Iterable
.
Editar
@Andreas ha señalado en los comentarios que Iterable
solo se introdujo en Java 5, mientras que Collection
se introdujo en Java 1.2, y que la mayoría de los métodos existentes que toman una Collection
no se pueden adaptar para que se pueda Iterable
por razones de compatibilidad.
Para responder a la pregunta según el título:
¿Hay alguna clase estándar de Java que implemente
Iterable
sin implementarCollection
?
Del texto:
Si alguna vez hay clases que pueden implementar
Iterable<T>
que no implementan tambiénCollection<T>
?
Responder:
Sí
Consulte la siguiente página javadoc: https://docs.oracle.com/javase/8/docs/api/java/lang/class-use/Iterable.html
Cualquier sección que diga Classes in XXX that implement Iterable
, enumerará las clases estándar de Java que implementan la interfaz. Muchos de los que no implementan Collection
.