En muchos otros idiomas, p. Ej. Haskell, es fácil repetir un valor o una función varias veces, p. Ej. para obtener una lista de 8 copias del valor 1:
take 8 (repeat 1)
pero no he encontrado esto todavía en Java 8. ¿Existe tal función en el JDK de Java 8?
O alternativamente algo equivalente a un rango como
[1..8]
Parecería un reemplazo obvio para una declaración detallada en Java como
for (int i = 1; i <= 8; i++) {
System.out.println(i);
}
tener algo como
Range.from(1, 8).forEach(i -> System.out.println(i))
aunque este ejemplo en particular no parece mucho más conciso en realidad ... pero con suerte es más legible.

Respuestas:
Para este ejemplo específico, puede hacer:
Si necesita un paso diferente de 1, puede utilizar una función de mapeo, por ejemplo, para un paso de 2:
O cree una iteración personalizada y limite el tamaño de la iteración:
fuente
IntStream.rangeClosed(1, 8).forEach(i -> methodNoArgs());) pero confunde algo en mi opinión y en ese caso parece indicado un bucle.Aquí hay otra técnica que encontré el otro día:
los
Collections.nCopiesllamada crea unListcontenido dencopias de cualquier valor que proporcione. En este caso, es elIntegervalor en caja 1. Por supuesto, en realidad no crea una lista connelementos; crea una lista "virtualizada" que contiene solo el valor y la longitud, y cualquier llamada agetdentro del rango solo devuelve el valor. ElnCopiesmétodo ha existido desde que se introdujo el marco de colecciones en JDK 1.2. Por supuesto, la capacidad de crear una secuencia a partir de su resultado se agregó en Java SE 8.Gran cosa, otra forma de hacer lo mismo en aproximadamente el mismo número de líneas.
Sin embargo, esta técnica es más rápido que el
IntStream.generateyIntStream.iteratese acerca, y sorprendentemente, también es más rápido que elIntStream.rangeenfoque.por
iterateygenerateel resultado quizás no sea demasiado sorprendente. El marco de transmisiones (en realidad, los divisores de estas transmisiones) se basa en la suposición de que las lambdas generarán potencialmente diferentes valores cada vez, y que generarán un número ilimitado de resultados. Esto hace que la división en paralelo sea particularmente difícil. Eliteratemétodo también es problemático para este caso porque cada llamada requiere el resultado de la anterior. Entonces, los flujos que usangenerateyiterateno funcionan muy bien para generar constantes repetidas.El rendimiento relativamente bajo de
rangees sorprendente. Esto también está virtualizado, por lo que no todos los elementos existen en la memoria, y el tamaño se conoce de antemano. Esto debería hacer un spliterator rápido y fácilmente paralelizable. Pero sorprendentemente no le fue muy bien. Quizás la razón es querangetiene que calcular un valor para cada elemento del rango y luego llamar a una función sobre él. Pero esta función simplemente ignora su entrada y devuelve una constante, por lo que me sorprende que esto no esté alineado y eliminado.La
Collections.nCopiestécnica tiene que hacer boxing / unboxing para poder manejar los valores, ya que no existen especializaciones primitivas deList. Dado que el valor es el mismo cada vez, básicamente está encuadrado una vez y ese cuadro es compartido por todas lasncopias. Sospecho que el boxeo / unboxing está altamente optimizado, incluso intrinsificado, y puede insertarse bien.Aquí está el código:
Y aquí están los resultados de JMH: (2.8GHz Core2Duo)
Hay una buena cantidad de variación en la versión ncopies, pero en general parece cómodamente 20 veces más rápida que la versión de rango. (Sin embargo, estaría dispuesto a creer que hice algo mal).
Me sorprende lo bien que funciona la
nCopiestécnica. Internamente, no es muy especial, ya que el flujo de la lista virtualizada simplemente se implementa usandoIntStream.range! Esperaba que fuera necesario crear un spliterator especializado para que esto fuera rápido, pero ya parece bastante bueno.fuente
nCopiesrealidad no copia nada y que todas las "copias" apuntan a ese único objeto. Siempre es seguro si ese objeto es inmutable , como una primitiva en caja en este ejemplo. Usted hace alusión a esto en su declaración "encajonado una vez", pero sería bueno mencionar explícitamente las advertencias aquí porque ese comportamiento no es específico del auto-boxing.LongStream.rangees significativamente más lento queIntStream.range? Así que es bueno que se haya descartado la idea de no ofrecer unIntStream(pero usarloLongStreampara todos los tipos de enteros). Tenga en cuenta que para el caso de uso secuencial, no hay ninguna razón para usar la transmisión en absoluto:Collections.nCopies(8, 1).forEach(i -> System.out.println(i));hace lo mismo,Collections.nCopies(8, 1).stream().forEach(i -> System.out.println(i));pero podría ser incluso más eficienteCollections.<Runnable>nCopies(8, () -> System.out.println(1)).forEach(Runnable::run);LongStream.rangefuncione peor, porque tiene dos mapas con elLongFunctioninterior, mientras quencopiestiene tres mapas conIntFunction,ToLongFunctionyLongFunction, por lo tanto, todas las lambdas son monomórficas. La ejecución de esta prueba en un perfil de tipo precontaminado (que está más cerca del caso del mundo real) muestra quencopieses 1,5 veces más lento.forciclo antiguo simple . Si bien su solución es más rápida que elStreamcódigo, supongo que unforbucle superaría a cualquiera de estos por un margen significativo.Para completar, y también porque no pude evitarlo :)
Generar una secuencia limitada de constantes está bastante cerca de lo que vería en Haskell, solo con nivel de detalle de Java.
fuente
() -> 1solo generaría 1, ¿está previsto? Entonces la salida sería1 1 1 1 1 1 1 1.take 8 (repeat 1). Assylias cubrió prácticamente todos los demás casos.Stream<T>también tiene ungeneratemétodo genérico para obtener un flujo infinito de algún otro tipo, que puede limitarse de la misma manera.Una vez que una función de repetición se define en algún lugar como
Puede usarlo de vez en cuando de esta manera, por ejemplo:
Para obtener y equivalente a Haskell
Podrías escribir
fuente
RunnableaFunction<Integer, ?>y luego utilizandof.apply(i).Esta es mi solución para implementar la función de tiempos. Soy un junior, así que admito que podría no ser ideal, me alegraría saber si esto no es una buena idea por cualquier motivo.
Aquí hay un ejemplo de uso:
fuente