sirve settitle que para definicion java java-8

definicion - para que sirve settitle en java



¿Java 8 proporciona una buena manera de repetir un valor o función? (4)

En muchos otros idiomas, ej. Haskell, es fácil repetir un valor o función varias veces, ej. para obtener una lista de 8 copias del valor 1:

take 8 (repeat 1)

pero aún no lo he encontrado en Java 8. ¿Hay una 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 así como

Range.from(1, 8).forEach(i -> System.out.println(i))

aunque este ejemplo particular no parece mucho más conciso en realidad ... pero con suerte es más legible.


Aquí hay otra técnica que encontré el otro día:

Collections.nCopies(8, 1) .stream() .forEach(i -> System.out.println(i));

La llamada Collections.nCopies crea una List contiene n copias de cualquier valor que proporciones. En este caso, es el valor Integer 1. Por supuesto, en realidad no crea una lista con n elementos; crea una lista "virtualizada" que contiene solo el valor y la longitud, y cualquier llamada para get dentro del rango simplemente devuelve el valor. El método nCopies ha existido desde que se introdujo el Framework de Colecciones desde el 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ápida que los IntStream.generate e IntStream.iterate , y sorprendentemente, también es más rápido que el enfoque de IntStream.range .

Para iterate y generate el resultado quizás no sea demasiado sorprendente. El marco de flujos (en realidad, los Spliterators para estas secuencias) 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 paralela sea particularmente difícil. El método iterate también es problemático para este caso porque cada llamada requiere el resultado de la anterior. Entonces las secuencias que usan generate e iterate no funcionan muy bien para generar constantes repetidas.

El rendimiento relativamente bajo del range es sorprendente. Esto también está virtualizado, por lo que los elementos en realidad no existen en la memoria, y el tamaño se conoce desde el principio. 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 que el range tiene que calcular un valor para cada elemento del rango y luego llamar una función sobre él. Pero esta función simplemente ignora su entrada y devuelve una constante, por lo que estoy sorprendido de que no esté en línea y asesinado.

La técnica Collections.nCopies tiene que hacer boxeo / unboxing para manejar los valores, ya que no hay especializaciones primitivas de List . Como el valor es el mismo siempre, básicamente se encuadra una vez y todas las n copias comparten esa caja. Sospecho que el boxeo / unboxing está altamente optimizado, incluso intrínseco, y puede ser bien alineado.

Aquí está el código:

public static final int LIMIT = 500_000_000; public static final long VALUE = 3L; public long range() { return LongStream.range(0, LIMIT) .parallel() .map(i -> VALUE) .map(i -> i % 73 % 13) .sum(); } public long ncopies() { return Collections.nCopies(LIMIT, VALUE) .parallelStream() .mapToLong(i -> i) .map(i -> i % 73 % 13) .sum(); }

Y aquí están los resultados de JMH: (2.8GHz Core2Duo)

Benchmark Mode Samples Mean Mean error Units c.s.q.SO18532488.ncopies thrpt 5 7.547 2.904 ops/s c.s.q.SO18532488.range thrpt 5 0.317 0.064 ops/s

Hay una gran cantidad de variación en la versión de ncopies, pero en general parece cómodamente 20 veces más rápido que la versión de rango. (Sin embargo, estaría bastante dispuesto a creer que he hecho algo mal).

Me sorprende lo bien que funciona la técnica de nCopies . Internamente, no es muy especial, ¡con la secuencia de la lista virtualizada simplemente implementada usando IntStream.range ! Esperaba que fuera necesario crear un spliterator especializado para que esto funcione rápido, pero ya parece ser bastante bueno.


Para completar, y también porque no pude evitarlo :)

Generar una secuencia limitada de constantes es bastante similar a lo que verías en Haskell, solo que con el nivel de detalle de Java.

IntStream.generate(() -> 1) .limit(8) .forEach(System.out::println);


Para este ejemplo específico, podrías hacer:

IntStream.rangeClosed(1, 8) .forEach(System.out::println);

Si necesita un paso diferente de 1, puede usar una función de mapeo, por ejemplo, para un paso de 2:

IntStream.rangeClosed(1, 8) .map(i -> 2 * i - 1) .forEach(System.out::println);

O crea una iteración personalizada y limita el tamaño de la iteración:

IntStream.iterate(1, i -> i + 2) .limit(8) .forEach(System.out::println);


Una vez que una función de repetición se define en algún lugar como

public static BiConsumer<Integer, Runnable> repeat = (n, f) -> { for (int i = 1; i <= n; i++) f.run(); };

Puede usarlo de vez en cuando de esta manera, por ejemplo:

repeat.accept(8, () -> System.out.println("Yes"));

Para obtener y equivalente a Haskell''s

take 8 (repeat 1)

Podrías escribir

StringBuilder s = new StringBuilder(); repeat.accept(8, () -> s.append("1"));