Una de las nuevas características java8: la transmisión de datos de tratamiento (incluida la lista, mapa de procesamiento de datos).

I. Introducción Streaming

Cuando entro en contacto con java8 transmitido, mi primera impresión se transmite a hacer una gran cantidad de operaciones de ajuste se convierten en simples, por lo general necesitan varias líneas de código para completar la operación por medio de la transmisión puede ser implementado en una fila . Por ejemplo, queremos un conjunto de números enteros que comprenden todo, incluso filtrada, y lo encapsula en una nueva lista devuelta, a continuación, antes java8, necesitamos ser alcanzado por el siguiente código:

List<Integer> evens = new ArrayList<>();
for (final Integer num : nums) {
    if (num % 2 == 0) {
        evens.add(num);
    }
}

Por el procesamiento de streaming java8, podemos simplificar el código es:

List<Integer> evens = nums.stream().filter(num -> num % 2 == 0).collect(Collectors.toList());

Brevemente explique la afirmación anterior es el significado de esta línea, stream()la operación se convierte en un conjunto de flujo, filter()la implementación de nuestra costumbre proceso de selección, que aquí son seleccionados por todas las expresiones incluso lambda, que finalmente se pasa collect()el proceso de encapsulación resultados, y por Collectors.toList()designamos que se empaqueta en una colección devuelta lista.

Como puede verse en el ejemplo anterior, java8 streaming de procesamiento simplifica en gran medida la operación de recogida, de hecho, no sólo es la colección, incluyendo matrices, archivos, etc., con tal de que se puede convertir en una corriente, podemos usar el streaming, nos gusta escribir sentencias SQL como para manipularlo. java8 logrado por convección dentro de proceso iterativo, una corriente de proceso se puede dividir en tres partes: la corriente se convierte en la operación intermedia, el funcionamiento del terminal. La figura siguiente:

En un conjunto de ejemplo, una largada operativo que primero tiene que llamar a stream()la función para convertirlo en un arroyo, y luego llama a la apropiada 中间操作para lograr la necesidad de hacerlo para la colección, como el cribado, la conversión y, finalmente, por 终端操作la encapsulación de los resultados de la anterior volver a la forma que necesitamos.

Dos operación intermedia

Definimos a los estudiantes de la clase de entidad sencilla, por ejemplo demuestra este último:

public class Student {

    /** 学号 */
    private long id;

    private String name;

    private int age;

    /** 年级 */
    private int grade;

    /** 专业 */
    private String major;

    /** 学校 */
    private String school;

    // 省略getter和setter
}
// 初始化
List<Student> students = new ArrayList<Student>() {
    {
        add(new Student(20160001, "孔明", 20, 1, "土木工程", "武汉大学"));
        add(new Student(20160002, "伯约", 21, 2, "信息安全", "武汉大学"));
        add(new Student(20160003, "玄德", 22, 3, "经济管理", "武汉大学"));
        add(new Student(20160004, "云长", 21, 2, "信息安全", "武汉大学"));
        add(new Student(20161001, "翼德", 21, 2, "机械与自动化", "华中科技大学"));
        add(new Student(20161002, "元直", 23, 4, "土木工程", "华中科技大学"));
        add(new Student(20161003, "奉孝", 23, 4, "计算机科学", "华中科技大学"));
        add(new Student(20162001, "仲谋", 22, 3, "土木工程", "浙江大学"));
        add(new Student(20162002, "鲁肃", 23, 4, "计算机科学", "浙江大学"));
        add(new Student(20163001, "丁奉", 24, 5, "土木工程", "南京大学"));
    }
};

2.1 filtro

Filtrado, por definición está de acuerdo con los requisitos de un determinado conjunto de elementos de filtro satisfacer un procedimiento de detección condición java8 incluyen: filtro, distinto, límite, saltar.

filtro
En el ejemplo anterior hemos demostrado cómo utilizar el filtro, que se define como: Stream<T> filter(Predicate<? super T> predicate), filtro toma un predicado Predicate, el predicado podemos definir una condición de filtro, cuando se introdujo la expresión introducción lambda Predicatees una interfaz de función, que contiene un test(T t)método devuelve boolean. Ahora queremos de la colección studentsfiltrar todos los estudiantes de la Universidad de Wuhan, entonces podemos lograr a través del filtro, y la operación del filtro como un parámetro que se pasa al filtro:

List<Student> whuStudents = students.stream()
                                    .filter(student -> "武汉大学".equals(student.getSchool()))
                         
           .collect(Collectors.toList());

distinta
operación distinta es similar a cuando escribimos las instrucciones SQL, añadir DISTINCTpalabras clave, vaya para su reprocesamiento, basado en distinta Object.equals(Object)dado cuenta, de nuevo al principio del ejemplo, supongamos que queremos filtrar toda la no repetición de número par, se puede añadir operaciones distintas :

List<Integer> evens = nums.stream()
                        .filter(num -> num % 2 == 0).distinct()
                        .collect(Collectors.toList());

límite de
operaciones de límite son similares a la instrucción SQL LIMITpalabras clave, pero la función es relativamente débil, limitar el flujo de retorno que contiene los primeros n elementos, cuando el tamaño del conjunto es menor que n, se devuelve la longitud real, como en el ejemplo siguiente devuelve la dos primera Profesional para los 土木工程mayores:

List<Student> civilStudents = students.stream()
                                    .filter(student -> "土木工程".equals(student.getMajor())).limit(2)
                                    .collect(Collectors.toList());

Hablando límite, tengo que mencionar sobre otra operación de flujo: sorted. Los elementos de mando para la convección especie, ordenados requisitos para ser elemento de comparación debe implementar Comparablela interfaz, si no se dio cuenta de que no importa, podemos comparar se pasa como un parámetro a sorted(Comparator<? super T> comparator), por ejemplo, queremos filtrar el estudiante de ingeniería civil de carrera, y pulse la edad, de pequeño a grande, proyectado dos estudiantes más jóvenes, puede ser implementado como:

List<Student> sortedCivilStudents = students.stream()
                                            .filter(student -> "土木工程".equals(student.getMajor())).sorted((s1, s2) -> s1.getAge() - s2.getAge())
                                            .limit(2)
                                            .collect(Collectors.toList());

Saltar
Saltar la operación y el límite de operación contraria, ya que su significado literal, es saltarse los primeros n elementos, por ejemplo, queremos averiguar la especie en Ingeniería Civil 2 después de que los estudiantes, puede ser implementado como:

List<Student> civilStudents = students.stream()
                                    .filter(student -> "土木工程".equals(student.getMajor()))
                                    .skip(2)
                                    .collect(Collectors.toList());

Por Skip, se saltará los dos primeros elementos, todos los elementos de la secuencia devuelta por la longitud de la estructura de respaldo, si n es mayor que la satisfacción de las condiciones establecidas, devuelven un conjunto vacío.

2.2 Mapeo

En SQL, con el SELECTcampo necesita nombres que añadir palabras clave de espalda, sólo podrá datos de campo de exportación que necesitamos, y la operación de asignación se transmite a lograr este propósito, en java8 streaming de procesamiento, contiene principalmente dos tipos de operaciones de mapeo : mapa y flatMap.

mapear
ilustración, basado en la suposición de que queremos filtrar todo el nombre de la computadora del estudiante profesional de la ciencia, por lo que podemos filtrar en el filtro, mediante la asignación de un mapa físico de los estudiantes como cadena de nombre de un estudiante, específicamente para lograr lo siguiente:

List<String> names = students.stream()
                            .filter(student -> "计算机科学".equals(student.getMajor()))
                            .map(Student::getName).collect(Collectors.toList());

Además de lo anterior, tales mapa base, java8 también proporciona mapToDouble(ToDoubleFunction<? super T> mapper),, mapToInt(ToIntFunction<? super T> mapper), mapToLong(ToLongFunction<? super T> mapper)estos mapas que corresponden respectivamente al tipo de flujo de retorno, java8 a establecer algunas acciones especiales con la corriente, como profesional, ya que queremos contar todas las edades y de los estudiantes de informática , entonces podemos lograr lo siguiente:

int totalAge = students.stream()
                    .filter(student -> "计算机科学".equals(student.getMajor()))
                    .mapToInt(Student::getAge).sum();

Por Estudiante asigna directamente según la edad IntStream, podemos llamar directamente a proporcionar sum()un método para lograr sus objetivos, además de los beneficios del uso de estos valores es también para evitar la operación de boxeo JVM flujo provocada por el consumo de rendimiento.

flatMap
mapa de diferencias y en que flatMap  flatMap cada valor de una corriente se transforma en una corriente, y luego aplanadas en la que fluye una corriente  . Por ejemplo, supongamos que tenemos una matriz de cadenas String[] strs = {"java8", "is", "easy", "to", "use"};, queremos exportar todas carácter de carácter distinto de la matriz, entonces podríamos pensar primero a lograr lo siguiente:

List<String[]> distinctStrs = Arrays.stream(strs)
                                .map(str -> str.split(""))  // 映射成为Stream<String[]>
                                .distinct()
                                .collect(Collectors.toList());

for(String[] strings : distinctStrs){ System.out.printLn(ArraystoString(strings)); }Después de realizar el mapa operación, se obtiene una corriente que comprende una pluralidad de cadenas (cadenas que constituyen una matriz de caracteres), en cuyo caso realizar operaciones distintas se basan en una comparación entre la matriz de cadena, por lo que queremos alcance propósito, se emite en este momento:

[j, a, v, a, 8]
[i, s]
[e, a, s, y]
[t, o]
[u, s, e]

Sólo para una corriente distinta contiene más caracteres para operar con el fin de lograr nuestros objetivos, a saber, Stream<String>las operaciones de llevar a cabo. En este punto flatMap podemos lograr nuestro objetivo:

List<String> distinctStrs = Arrays.stream(strs)
                                .map(str -> str.split(""))  // 映射成为Stream<String[]>
                                .flatMap(Arrays::stream)  // 扁平化为Stream<String>
                                .distinct()
                                .collect(Collectors.toList());

mapa obtenido mediante mapeo flatMap Stream<String[]>, en el mapeado en una matriz de cadenas por el flujo respectivo Stream<String>, estas pequeñas corrientes y luego aplanadas en un rebaño que consiste en todas las cadenas Steam<String>, es posible lograr nuestro propósito.
Al igual que en el mapa, flatMap también proporciona una operación de asignación de tipos específicos: flatMapToDouble(Function<? super T,? extends DoubleStream> mapper), flatMapToInt(Function<? super T,? extends IntStream> mapper), flatMapToLong(Function<? super T,? extends LongStream> mapper).

III. Operación Terminal

el funcionamiento del terminal es el último paso de la corriente de proceso, podemos lograr una operación de búsqueda de convección en el terminal, reducción y otras operaciones.

Encuentra 3.1

allmatch
allmatch utiliza para detectar si todos cumplen con el comportamiento de los parámetros especificados, si todas las devoluciones satisfechos cierto, por ejemplo, queremos comprobar si todos los estudiantes están por lo menos 18 años de edad, que pueden ser implementados como:

boolean isAdult = students.stream().allMatch(student -> student.getAge() >= 18);

AnyMatch
AnyMatch es detectar la presencia de uno o más parámetros para satisfacer comportamiento especificado, devuelve verdadero si el se encuentran, por ejemplo, queremos detectar si hay estudiantes de la Universidad de Wuhan, que pueden ser implementados como:

boolean hasWhu = students.stream().anyMatch(student -> "武汉大学".equals(student.getSchool()));

noneMathch
noneMatch para detectar el comportamiento cumple con el elemento especificado no existe, entonces no hay retorno si es cierto, por ejemplo, queremos detectar si profesional para estudiantes de informática no existe, se puede lograr lo siguiente:

boolean noneCs = students.stream().noneMatch(student -> "计算机科学".equals(student.getMajor()));

findFirst
findFirst utiliza para devolver el primer elemento para cumplir con las condiciones, tales como queremos elegir a un estudiante de ingeniería civil de carrera en la primera fila, se puede lograr lo siguiente:

Optional<Student> optStu = students.stream().filter(student -> "土木工程".equals(student.getMajor())).findFirst();

findFirst no llevar a los parámetros, criterios de búsqueda específicos pueden ser ajustados por el filtro, además podemos encontrar findFirst de retorno es un tipo opcional.

findAny
findAny diferencia relativa findFirst es que, findAny no necesariamente volver a la primera, pero un retorno a arbitraria, por ejemplo, queremos devolver cualquiera de los estudiantes profesionales de ingeniería civil puede lograr lo siguiente:

Optional<Student> optStu = students.stream().filter(student -> "土木工程".equals(student.getMajor())).findAny();

De hecho para la transmisión secuencial, y los resultados de retorno findFirst findAny es lo mismo, en cuanto a porqué este diseño, ya que la siguiente estamos introduciendo transmisión en paralelo , cuando nos permitimos ver en streaming en paralelo el primer elemento será siempre un montón de restricciones, si no necesidades especiales, utilice el rendimiento de findAny findFirst en paralelo de streaming en el pozo.

3.2 Reducción

En el ejemplo anterior que en su mayoría por collect(Collectors.toList())los datos devueltos paquete, como mi objetivo no devuelve un nuevo conjunto, sino a una parametrizado después de la operación de recogida para su posterior cálculo, entonces podemos utilizar la modalidad de reducción de colección operación. java8 proceso de transmisión proporciona reduceun método para lograr este propósito.

Vamos a mapToInt frontal Stream<Student>asignada a IntStream, ya través del IntStreammétodo de la suma determinada la edad de todos los estudiantes y, de hecho, pasamos una operación de reducción, se puede lograr este objetivo, para lograr lo siguiente:

// 前面例子中的方法
int totalAge = students.stream()
                .filter(student -> "计算机科学".equals(student.getMajor()))
                .mapToInt(Student::getAge).sum();
// 归约操作
int totalAge = students.stream()
                .filter(student -> "计算机科学".equals(student.getMajor()))
                .map(Student::getAge)
                .reduce(0, (a, b) -> a + b);

// 进一步简化
int totalAge2 = students.stream()
                .filter(student -> "计算机科学".equals(student.getMajor()))
                .map(Student::getAge)
                .reduce(0, Integer::sum);

// 采用无初始值的重载版本,需要注意返回Optional
Optional<Integer> totalAge = students.stream()
                .filter(student -> "计算机科学".equals(student.getMajor()))
                .map(Student::getAge)
                .reduce(Integer::sum);  // 去掉初始值

3.3 colección

Frente usando collect(Collectors.toList())una operación de recolección simple, el paquete es un resultado de procesamiento, así como correspondiente toSet, toMappara satisfacer nuestra necesidad de resultados de tejidos. Estos métodos son de java.util.stream.Collectors, podemos llamar al colector.

3.3.1 Reducción

Collector también proporciona una operación de reducción correspondiente, pero en el interior y reducir aplicación es diferente, más adecuado para las operaciones de reducción variable de colector en el contenedor, estos se basan en el colector generalizado Collectors.reducing()aplicación.

Ejemplo 1: Encuentre el número total de estudiantes

long count = students.stream().collect(Collectors.counting());

// 进一步简化
long count = students.stream().count();

Ejemplo 2: Encuentre el máximo y el mínimo de edad

// 求最大年龄
Optional<Student> olderStudent = students.stream().collect(Collectors.maxBy((s1, s2) -> s1.getAge() - s2.getAge()));

// 进一步简化
Optional<Student> olderStudent2 = students.stream().collect(Collectors.maxBy(Comparator.comparing(Student::getAge)));

// 求最小年龄
Optional<Student> olderStudent3 = students.stream().collect(Collectors.minBy(Comparator.comparing(Student::getAge)));

Ejemplo 3: Edad para la obtención de la suma

int totalAge4 = students.stream().collect(Collectors.summingInt(Student::getAge));

Hay correspondientes summingLong, summingDouble.

Ejemplo 4: edad promedio

double avgAge = students.stream().collect(Collectors.averagingInt(Student::getAge));

Hay correspondientes averagingLong, averagingDouble.

Ejemplo 5: un número de una sola vez de elementos, la suma, la media, máximo, mínimo

IntSummaryStatistics statistics = students.stream().collect(Collectors.summarizingInt(Student::getAge));

salida:

IntSummaryStatistics{count=10, sum=220, min=20, average=22.000000, max=24}

Hay correspondientes summarizingLong, summarizingDouble.

Ejemplo 6: la concatenación de cadenas

String names = students.stream().map(Student::getName).collect(Collectors.joining());
// 输出:孔明伯约玄德云长翼德元直奉孝仲谋鲁肃丁奉
String names = students.stream().map(Student::getName).collect(Collectors.joining(", "));
// 输出:孔明, 伯约, 玄德, 云长, 翼德, 元直, 奉孝, 仲谋, 鲁肃, 丁奉

3.3.2 Paquete

En las operaciones de base de datos, podemos GROUP BYagrupar datos a las palabras clave de consulta, java8 proceso de streaming también ofrecemos esta funcionalidad Collectors.groupingByal conjunto de operaciones. Por ejemplo, podemos superar los estudiantes se agrupan por la escuela:

Map<String, List<Student>> groups = students.stream().collect(Collectors.groupingBy(Student::getSchool));

groupingByRecepción de un clasificador Function<? super T, ? extends K> classifier, podemos encargo clasificadores para lograr los resultados de la clasificación necesarios.

anterior se ilustra un grupo, también podemos definir varios clasificadores para lograr  varios niveles de agrupamiento , como deseamos ser agrupadas por dedique profesionalmente por la escuela en el grupo para lograr lo siguiente:

Map<String, Map<String, List<Student>>> groups2 = students.stream().collect(
                Collectors.groupingBy(Student::getSchool,  // 一级分组,按学校
                Collectors.groupingBy(Student::getMajor)));  // 二级分组,按专业

De hecho, groupingByel segundo argumento no sólo es pasar groupingBy, también puede pasar cualquier Collectortipo, por ejemplo, podemos pasar una Collector.countingpara contar el número de cada grupo:

Map<String, Long> groups = students.stream().collect(Collectors.groupingBy(Student::getSchool, Collectors.counting()));

Si no añadimos el segundo argumento, el compilador nos ayudará a añadir un valor predeterminado Collectors.toList().

3.3.3 partición

Partición se puede ver como un caso especial de paquetes, clave en el caso de sólo dos particiones: verdadero o falso, el objeto ha de ser dividido en dos de acuerdo con las condiciones establecidas, java8 usando el streaming de ollectors.partitioningBy()método implementado de partición, el método recibir un predicado, por ejemplo, esperamos que los estudiantes se dividirán en los estudiantes universitarios estudiantes universitarios militares y no militares, se puede lograr lo siguiente:

Map<Boolean, List<Student>> partition = students.stream().collect(Collectors.partitioningBy(student -> "武汉大学".equals(student.getSchool())));

Partición de paquetes ventaja relativa es que podemos obtener dos tipos de resultados, al mismo tiempo, puede obtener todos los resultados que necesitamos a paso en algunos escenarios, como por ejemplo la matriz se divide en pares e impares.

Todos los colectores han logrado a partir de la descripción anterior de la interfaz java.util.stream.Collector, la interfaz se define como sigue:

public interface Collector<T, A, R> {
    /**
     * A function that creates and returns a new mutable result container.
     *
     * @return a function which returns a new, mutable result container
     */
    Supplier<A> supplier();

    /**
     * A function that folds a value into a mutable result container.
     *
     * @return a function which folds a value into a mutable result container
     */
    BiConsumer<A, T> accumulator();

    /**
     * A function that accepts two partial results and merges them.  The
     * combiner function may fold state from one argument into the other and
     * return that, or may return a new result container.
     *
     * @return a function which combines two partial results into a combined
     * result
     */
    BinaryOperator<A> combiner();

    /**
     * Perform the final transformation from the intermediate accumulation type
     * {@code A} to the final result type {@code R}.
     *
     * <p>If the characteristic {@code IDENTITY_TRANSFORM} is
     * set, this function may be presumed to be an identity transform with an
     * unchecked cast from {@code A} to {@code R}.
     *
     * @return a function which transforms the intermediate result to the final
     * result
     */
    Function<A, R> finisher();

    /**
     * Returns a {@code Set} of {@code Collector.Characteristics} indicating
     * the characteristics of this Collector.  This set should be immutable.
     *
     * @return an immutable set of collector characteristics
     */
    Set<Characteristics> characteristics();

}

También podemos implementar esta interfaz para definir su propia trampa, ya no ampliar aquí.

IV. Procesamiento de datos de streaming paralelas

Streaming Muchos son adecuados para  divide y vencerás  pensamientos, y en el tratamiento de grandes colecciones, lo que mejora considerablemente el rendimiento del código, los diseñadores han visto este java8, por lo que proporciona  transmisión en paralelo . En el ejemplo anterior que llamamos stream()método para iniciar la transmisión, java8 también proporcionado parallelStream()para iniciar el proceso de flujo paralelo, parallelStream()basado en el marco de unirse y Tenedor Java7 esencialmente logra, el número predeterminado de hilos para el número de núcleos del huésped.

inicio paralelo de streaming es simple, sólo es necesario stream()sustituir parallelStream()la lata, pero ya que es un paralelo, multi-hilo implicará problemas de seguridad, por lo que antes de habilitar primero confirme paralelo si vale la pena (no necesariamente más alta que la eficiencia de la orden de ejecución en paralelo ), el otro es para garantizar la seguridad hilo. Esta dos no se puede garantizar, entonces el sentido paralelo, después de todo, el resultado es más importante que la velocidad, después de un tiempo nuevo analizar en detalle la aplicación específica y las mejores prácticas de procesamiento de datos del flujo paralelo.

Publicó un artículo original · ganado elogios 1 · vistas 73

Supongo que te gusta

Origin blog.csdn.net/f_u_c_k_le/article/details/105276953
Recomendado
Clasificación