Nuevas características de JDK8 - Notas de estudio

Link de la nota Sparrow:
https://www.yuque.com/g/u22538081/ghlpft/zcbyis/collaborator/join?token=pofOuJabmo9rgKvS# Te invitamos a ver el documento "Programación Funcional - Nuevas Funcionalidades de jdk"

¿Por qué estudiar?

Comprender el código de la empresa
Alta eficiencia en el procesamiento de cobros en grandes cantidades
Alta legibilidad del código
Eliminar el infierno de anidamiento

concepto

El pensamiento orientado a objetos necesita enfocarse en qué objetos hacen qué
, mientras que el pensamiento de programación funcional es similar a las funciones en nuestras matemáticas, se enfoca principalmente en qué operaciones se realizan en los datos.

ventaja

Código simple, desarrollo rápido
Cercano al lenguaje natural, fácil de entender
Fácil "programación concurrente"

expresión lambda

concepto

Azúcar sintáctico
Simplificar la escritura de algunas clases internas anónimas.
Centrarse más en lo que hacemos con los datos.

centro

Puede derivarse u omitirse

formato básico

(lista de parámetros) —> {código}

ejemplo uno

Previamente, creando un hilo para iniciar una clase interna anónima

new Thread(new Runnable() {
    
    
    @Override
    public void run() {
    
    
        System.out.println("新线程中run方法被执行了");
    }
}).start();

Después de usar lambda

		/**
		 * 什么时候可以用lambda简化呢?
		 * 	1、如果匿名内部类是一个接口
		 * 	2、并且这个接口中只有一个方法需要重写(有多个就不好判断重写哪个了)
		 * 	【关注参数和方法体】
		 */
		new Thread(()-> {
    
    
			System.out.println("lambda表达式");
		}).start();

Ejemplo 2

package lambda;

import java.util.function.IntBinaryOperator;

public class LambdaDemo01 {
    
    
	public static void main(String[] args) {
    
    
		/**
		 * 原来的写法
		 */
		int i = calculateNum(new IntBinaryOperator() {
    
    
			@Override
			public int applyAsInt(int left, int right) {
    
    
				// TODO Auto-generated method stub
				return left + right;
			}
		});
		System.out.println(i);
		
		/**
		 * 使用lambda表达式
		 */
		int j = calculateNum((int left,int right) -> {
    
    
			return left + right;
		});
		System.out.println(j);
	
	}
	//IntBinaryOperator 是函数式接口
	public static int calculateNum(IntBinaryOperator operator) {
    
    
		int a = 10;
		int b = 20;
		return operator.applyAsInt(a, b);
	}
}

Tecla de método abreviado de idea, cambio a lambda
inserte la descripción de la imagen aquí

Tecla de atajo de idea, lambda se vuelve original
inserte la descripción de la imagen aquí

ejemplo tres

package lambda;

import java.util.function.IntBinaryOperator;
import java.util.function.IntPredicate;

public class LambdaDemo01 {
    
    
	public static void main(String[] args) {
    
    
		/**
		 * 原来的写法
		 */
		printNum(new IntPredicate() {
    
    
			
			@Override
			public boolean test(int value) {
    
    
				// TODO Auto-generated method stub
				return value%2 == 0;
			}
		});
		
		System.out.println("==================");
		
		/**
		 * 使用lambda表达式
		 */
		printNum((int value) -> {
    
    
			return value%2 == 0;
		});
		
	}
	//IntPredicate 是一个函数式接口
	public static void printNum(IntPredicate predicate) {
    
    
		int[] arr = {
    
    1,2,3,4,5,6,7,8,9,10};
		for(int i :arr) {
    
    
			if(predicate.test(i)) {
    
    
				System.out.println(i);
			}
		}
		
	}
	
}

ejemplo cuatro

package lambda;

import java.util.function.Function;

public class LambdaDemo01 {
    
    
	public static void main(String[] args) {
    
    

		/**
		 * 原来方式
		 */
		 Integer result = typeConver(new Function<String, Integer>() {
    
    

			@Override
			public Integer apply(String t) {
    
    
				// TODO Auto-generated method stub
				return Integer.valueOf(t);
			}
			
		});
		 
		System.out.println(result);
		
		/**
		 * 使用lambda表达式
		 */
		Integer result2 = typeConver((String t) -> {
    
    
			return Integer.valueOf(t);
		});
		System.out.println(result2);
		
	}
	//Function 是一个函数式接口	
	public static <R> R typeConver(Function<String,R>function) {
    
    
		String str = "1235";
		R result = function.apply(str);
		return result;
	}
	
}

ejemplo cinco

package lambda;

import java.util.function.Function;
import java.util.function.IntConsumer;

public class LambdaDemo01 {
    
    
	public static void main(String[] args) {
    
    

		/**
		 * 原来方式
		 */
		foreachArr(new IntConsumer() {
    
    
			
			@Override
			public void accept(int value) {
    
    
				// TODO Auto-generated method stub
				System.out.println(value);
			}
		});
		 
		
		/**
		 * 使用lambda表达式
		 */
		foreachArr((int value) -> {
    
    
			System.out.println(value);
		});
	}
	//Function 是一个函数式接口	
	public static void foreachArr(IntConsumer consumer) {
    
    
		int[] arr = {
    
    1,2,3,4,5,6,7,8,9,10};
		for(int i : arr) {
    
    
			consumer.accept(i);
		}
	}
}

reglas de omisión

El tipo de parámetro se puede omitir.
Cuando el cuerpo del método tiene solo una línea de código, se pueden omitir las llaves de retorno y el punto y coma de la única línea de código.
Cuando el método tiene solo un parámetro, se pueden omitir los paréntesis
. las reglas anteriores no se pueden recordar o se pueden omitir.

omitir ejemplo

package lambda;

import java.util.function.Function;
import java.util.function.IntConsumer;

public class LambdaDemo01 {
    
    
	public static void main(String[] args) {
    
    
		
		/**
		 * 使用lambda表达式
		 */
		foreachArr((int value) -> {
    
    
			System.out.println(value);
		});
		
		/**
		 * 省略后
		 */
		foreachArr(value -> System.out.println(value));
	}
	//Function 是一个函数式接口	
	public static void foreachArr(IntConsumer consumer) {
    
    
		int[] arr = {
    
    1,2,3,4,5,6,7,8,9,10};
		for(int i : arr) {
    
    
			consumer.accept(i);
		}
	}
}

Arroyo

1. Información general

Stream de Java8 utiliza un modelo de programación funcional. Al igual que su nombre, se puede usar para realizar operaciones de flujo en cadena en colecciones o matrices, lo que nos facilita operar en colecciones o matrices.

2. Preparación de datos de casos

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.22</version>
    </dependency>
</dependencies>

clase de autor

package com.sangeng;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.util.List;

@Data   //生成get和set
@NoArgsConstructor  //无参构造
@AllArgsConstructor //有参构造
@EqualsAndHashCode  //用于后期去重使用(重写equals和hashCode方法)
public class Author {
    
       //作者

    //id
    private Long id;
    //姓名
    private String name;
    //年龄
    private Integer age;
    //简介
    private String intro;
    //作品
    private List<Book> books;
}

Libros

package com.sangeng;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
public class Book {
    
    //书
    //id
    private Long id;
    //书名
    private String name;
    //分类
    private String category; //哲学,小说
    //评分
    private Integer score;
    //简介
    private String intro;

}

datos

package com.sangeng;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class StreamDemo {
    
    
    public static void main(String[] args) {
    
    

        List<Author> authors = getAuthors();
    }

    private static List<Author> getAuthors(){
    
    
        //数据初始化
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        Author author2 = new Author(2L,"亚拉索",15,"狂风也追逐不上他的思考速度",null);
        Author author3 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);
        Author author4 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);

        //书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L,"刀的两侧是光明与黑暗","哲学,爱情",88,"用一把划分了爱情"));
        books1.add(new Book(2L,"一个人同一把刀","个人成长,爱情",99,"讲述如何从"));

        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你去世界尽头"));
        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你去世界尽头"));
        books2.add(new Book(4L,"吹或不吹","爱情,个人传记",56,"一个哲学家的爱情"));

        books3.add(new Book(5L,"刀的两侧是光明与黑暗","爱情",56,"无法想象一个武者"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"讲述如何从"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"讲述如何从"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);


        List<Author> authorsList = new ArrayList<>(Arrays.asList(author,author2,author3,author4));

        return authorsList;
    }
}

3. Inicio rápido

Requisito:
podemos llamar al método getAuthors para obtener la colección de autores. Ahora debe imprimir los nombres de todos los escritores cuya edad sea menor de 18 años y prestar atención a la deduplicación.

lograr:

package com.sangeng;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

public class StreamDemo {
    
    
    public static void main(String[] args) {
    
    

        List<Author> authors = getAuthors();
        //System.out.println(authors);

        //打印所有年龄小于18的作家名字,并且要注意去重
        //filter过滤
        //forEach遍历
        authors.stream()    //stream()把集合转换成流
            .distinct()     //distinct()去重
            .filter(author -> author.getAge() < 18) //filter过滤【名字小于18】
            .forEach(author -> System.out.println(author.getName()));   //forEach遍历
    }

    private static List<Author> getAuthors(){
    
    
        //数据初始化
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        Author author2 = new Author(2L,"亚拉索",15,"狂风也追逐不上他的思考速度",null);
        Author author3 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);
        Author author4 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);

        //书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L,"刀的两侧是光明与黑暗","哲学,爱情",88,"用一把划分了爱情"));
        books1.add(new Book(2L,"一个人同一把刀","个人成长,爱情",99,"讲述如何从"));

        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你去世界尽头"));
        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你去世界尽头"));
        books2.add(new Book(4L,"吹或不吹","爱情,个人传记",56,"一个哲学家的爱情"));

        books3.add(new Book(5L,"刀的两侧是光明与黑暗","爱情",56,"无法想象一个武者"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"讲述如何从"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"讲述如何从"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);


        List<Author> authorsList = new ArrayList<>(Arrays.asList(author,author2,author3,author4));

        return authorsList;
    }
}

Operación de tecla rápida

estilo de flujo de depuración

El contenido de Java se convierte en método
inserte la descripción de la imagen aquí

4. Operación de rutina

1. Crea un flujo

Colección de una sola columna : objeto de colección.Stream

List<Author> authors = getAuthors();
Stream<Author> stream = authors.stream();

Array : Arrays.stream (array) o use Stream.of para crear

Integer[] arr = {
    
    1,2,3,4,5};
Stream<Integer> stream1 = Arrays.stream(arr);
Stream<Integer> stream2 = Stream.of(arr);

Colección de dos columnas : convertir a una colección de una sola columna y luego crear

Map<String,Integer> map = new HashMap<>();
map.put("垃圾公司",19);
map.put("黑子",17);
map.put("日向源",16);
Stream<Map.Entry<String,Integer>> stream3 = map.entrySet().stream();//entrySet()把map集合key,value封装成Set
//上一句分开
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
Stream<Map.Entry<String, Integer>> stream4 = entrySet.stream();

2. Operación intermedia

filtro filtro

Los elementos de la transmisión se pueden filtrar condicionalmente y solo aquellos que cumplen las condiciones del filtro pueden permanecer en la transmisión.

Ejemplo:
imprime los nombres de todos los escritores cuya longitud de nombre es mayor que 1

        //打印所有名字长度大于1的作家的姓名
        List<Author> authors = getAuthors();
        authors.stream()
                .filter(author -> author.getName().length() > 1)    //过滤 名字长度大于1
                .forEach(author -> System.out.println(author.getName()));

mapa

Puede calcular o transformar los elementos en la corriente de convección

Ejemplo:
imprimir todos los nombres de los escritores

        // map 打印所有作家的名字
        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getName())    //获取所有名字
                .forEach(name -> System.out.println(name));

        //map 所有年龄加10
        authors.stream()
                .map(author -> author.getAge())
                .map(age -> age + 10)
                .forEach(age -> System.out.println(age));

distinto

Los elementos duplicados se pueden eliminar

Por ejemplo:
imprimir los nombres de todos los autores y exigir que no haya elementos repetidos.
Nota: El método distinto se basa en el método de igualdad de Objeto para determinar si son el mismo objeto. Así que presta atención a reescribir el método de igualdad

        //打印所有作家的名字,并且要求其中不能有重复元素
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct() //去重
                .forEach(author -> System.out.println(author.getName()));

ordenado

los elementos en una secuencia se pueden ordenar

Por ejemplo:
ordene los elementos de la transmisión en orden descendente según la antigüedad y no requiera elementos duplicados.
Nota: si llama al método sorted() con parámetros vacíos, los elementos de la transmisión deben implementar la interfaz Comparable.

 //对流中的元素按照年龄进行降序排序,并且要求不能有重复元素
 List<Author> authors = getAuthors();
 authors.stream()
         .sorted() //排序 无参sorted()使用排序需要实现Comparable排序接口
         .distinct() //去重
         .forEach(author -> System.out.println(author.getName()));

 authors.stream()
         .distinct()
         .sorted((o1,o2) -> o2.getAge() - o1.getAge())   //排序 有参sorted直接匿名内部类实现Comparable排序接口
         .forEach(author -> System.out.println(author.getName()));

Ningún parámetro ordenado, los elementos en la transmisión deben implementar la interfaz Comparable

package com.sangeng;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.util.List;

@Data   //生成get和set
@NoArgsConstructor  //无参构造
@AllArgsConstructor //有参构造
@EqualsAndHashCode  //用于后期去重使用(重写equals和hashCode方法)
public class Author implements Comparable<Author>{
    
       //作者

    //id
    private Long id;
    //姓名
    private String name;
    //年龄
    private Integer age;
    //简介
    private String intro;
    //作品
    private List<Book> books;

    @Override
    public int compareTo(Author o) {
    
    
        return this.getAge() - o.getAge();
    }
}

límite

Se puede establecer la longitud máxima de la secuencia, y la parte sobrante se descartará.
Por ejemplo:
ordene los elementos de la secuencia en orden descendente según la edad, y exija que no haya elementos duplicados, y luego imprima los nombres de los dos escritores mas antiguos

//对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素,然后打印其中年龄最大的两个作家名字
List<Author> authors = getAuthors();
authors.stream()
    .distinct()// 去重
    .sorted((o1, o2) -> o2.getAge() - o1.getAge()) //排序,倒序
    .limit(2)   //设置流的最大长度,超出的部分将被抛弃
    .forEach(author -> System.out.println(author.getName() +" " +author.getAge()));

saltar

Omita los primeros n elementos en la secuencia y devuelva los elementos restantes
Por ejemplo:
imprima otros escritores excepto el escritor más antiguo, no requiera elementos duplicados y ordene en orden descendente de edad

 //打印除了年龄最大的作家外的其他作家,要求不能有重复元素,并且按照年龄降序排序
 List<Author> authors = getAuthors();
 authors.stream()
         .distinct() //去重
         .sorted((o1, o2) -> o2.getAge() - o1.getAge())  //降序排序
         .skip(1)    //skip 跳过流中的前n个元素,返回剩下的元素
         .forEach(author -> System.out.println(author.getName() +" " +author.getAge()));

mapa plano

map solo puede convertir un objeto en otro objeto como un elemento en la transmisión. Y flatMap puede convertir un objeto en múltiples objetos como elementos en la transmisión.
Ejemplo 1
Imprime los nombres de todos los libros y requiere que los elementos duplicados sean deduplicados.

 //map只能把一个对象转换成另一个对象来作为流中的元素。而flatMap可以把一个对象转换成多个对象作为流中的元素。
 //打印所有书籍的名字,要求对重复的元素进行去重。
 List<Author> authors = getAuthors();
 authors.stream()
         .flatMap(author -> author.getBooks().stream())  // 把获取到的所有一个个的书籍对象再转为流
         .distinct() //去重
         .forEach(book -> System.out.println(book));

 System.out.println("==========");
 authors.stream()
         .map(author -> author.getBooks())// 使用map的话,一个作者的书籍返回一个集合,不是一个个的书籍对象。
         .distinct()
         .forEach(book -> System.out.println(book));

Ejemplo 2
Imprime todas las clasificaciones de los datos existentes, lo que requiere desduplicación de clasificaciones, y este formato no puede aparecer: filosofía, amor.

//flatMap 打印现有数据的所有分类,要求对分类进行去重,不能出现这种格式:哲学,爱情。
List<Author> authors = getAuthors();
authors.stream()
    .flatMap(author -> author.getBooks().stream()) //获取所有书
    .distinct() //对书去重
    .flatMap(book -> Arrays.stream(book.getCategory().split(","))) //获取所有书的分类
    .distinct() //对数的分类去重
    .forEach(category -> System.out.println(category));

3. Fin de la operación

para cada

Para recorrer los elementos en la secuencia, pasamos parámetros para especificar qué operaciones específicas se realizarán en los elementos recorridos
Ejemplo:
mostrar los nombres de todos los escritores

//forEach 输出所有作家的名字
List<Author> authors = getAuthors();
authors.stream()
    .map(author -> author.getName())
    .distinct()
    .forEach(name -> System.out.println(name));

contar

Se puede usar para obtener la cantidad de elementos en el flujo actual
Ejemplo:
imprime la cantidad de libros publicados por estos autores, presta atención para eliminar los elementos duplicados

//count 打印这些作家的所出书籍的数目,注意删除重复元素
List<Author> authors = getAuthors();
long count = authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .distinct() //书信息进行去重
    .map(book -> book.getName())
    .distinct() //书名进行去重(由于我的测试数据,书名相同,但是有些分类写的是不同的)
    .count();   //计算 所有书的个数
System.out.println(count);

//老师这个【可能是没想到书名相同,但是分类没相同,这个是测试数据没写好】
long count1 = authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .distinct() //书信息进行去重
    .count();
System.out.println(count1);

máximo minimo

Se puede utilizar para obtener el valor más alto de la corriente
Ejemplo:
obtener las puntuaciones más altas y más bajas de los libros publicados por estos autores e imprimirlos.

//max min 分别获取这些作家的所出书籍的最高分和最低分并打印。
List<Author> authors = getAuthors();
Optional max = authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .map(book -> book.getScore() )
    .max((score1,score2) -> score1-score2);
System.out.println("最高评分 " + max.get());

Optional min = authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .map(book -> book.getScore() )
    .min((score1,score2) -> score1-score2);
System.out.println("最低评分 " + min.get());

recolectar

Convierta el flujo actual en una colección
Collectors.toList()
Collectors.toSet()
Collectors.toMap() [clave y valor]
Ejemplo:
obtenga una colección de listas que almacene el nombre del autor.

//collect
//获取一个存放说有作者名字的List集合。
List<Author> authors = getAuthors();
List<String> name = authors.stream()
    .map(author -> author.getName())
    .distinct()
    .collect(Collectors.toList());// 把流转换成List
System.out.println(name);

Obtenga una colección de conjuntos de todos los títulos de libros

// 获取一个所有书名的Set集合。
Set<String> bookName = authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .distinct()
    .map(book -> book.getName())
    .collect(Collectors.toSet());
System.out.println(bookName);

Obtenga una colección de mapas, la clave del mapa es el nombre del autor y el valor es una Lista [para escribir dos funciones, clave y valor]

// 获取一个map集合map的key为作者名,value为List<Book> 【map的话就要写两个方法】
Map<String,List<Book>> collect = authors.stream()
    .distinct()
    //map 两个返回值用“,”隔开(返回key,返回value)
    .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
System.out.println(collect);

Encuentra y combina anyMatch, allMatch, noneMatch

----------------fósforo---------------

cualquier partido

Se puede utilizar para juzgar si hay elementos que cumplen las condiciones de coincidencia, y el resultado es un tipo booleano
Ejemplo:
para juzgar si hay escritores mayores de 29 años

//anyMatch可以用来判断是否有任意符合匹配条件的元素,结果为Boolean类型
//例子:判断是否有年龄在29岁以上的作家
List<Author> authors = getAuthors();
Boolean test = authors.stream()
    .anyMatch(author -> author.getAge() > 29);
System.out.println(test);

todos los partidos

Se puede utilizar para juzgar si se cumplen todas las condiciones de coincidencia y el resultado es de tipo booleano. Si todos coinciden, el resultado es verdadero; de lo contrario, es falso
Ejemplo:
determine si todos los escritores son adultos

 //allMatch可以用来判断是否都符合匹配条件,结果为Boolean类型。如果都匹配结果为true,否则为false
 //例子:判断是否所有作家都成年了
 Boolean test2 = authors.stream()
         .allMatch(author -> author.getAge()>18);
 System.out.println(test2);
ningunaCoincidencia

Se puede juzgar si los elementos en el flujo no cumplen las condiciones correspondientes, si no cumplen el resultado, el resultado es verdadero, de lo contrario es falso Ejemplo: para juzgar si
el
escritor no tiene más de 100 años

 //noneMatch可以判断流中的元素是否都不符合匹配条件,如果都不符合结果为true,否则为false
 //例子:判断作家是否都没超过100岁
 Boolean test3 = authors.stream()
         .noneMatch(author -> author.getAge()>=100);
 System.out.println(test3);

----------------Encontrar---------------

encontrar cualquier

Obtenga cualquier elemento en la secuencia. Este método no garantiza que se deba obtener el primer elemento de la secuencia.
Ejemplo:
obtener cualquier escritor mayor de 18 años y mostrar su nombre si existe

 //findAny 获取流中的任意一个元素。该方法没有保证获取的一定是流中的第一个元素。
 //例子:获取任意一个大于18的作家,如果存在就输出他的名字
 List<Author> authors = getAuthors();
 Optional<Author> optionalAny = authors.stream()
         .filter(author -> author.getAge() > 18)
         .findAny();//获取流中的任意满足条件的一个元素

 //有问题,年龄改成0,还是同一个人(不是说是随机的吗?怎么还是第一个,是我代码有问题,还是概率问题)
 optionalAny.ifPresent(author -> System.out.println(author.getName()));
        
encontrarprimero

Obtenga el primer elemento en la secuencia.
Ejemplo:
obtener el escritor más joven y mostrar su nombre

//findFirst 获取流中的第一个元素。
//例子:获取一个年龄最小的作家,并输出他的姓名
List<Author> authors = getAuthors();
Optional<Author> first = authors.stream()
    .sorted((o1, o2) -> o1.getAge() - o2.getAge())
    .findFirst();

first.ifPresent(author -> System.out.println(author.getName()));

reducir fusionar

Convecte los datos en la secuencia para calcular un resultado (operación de reducción)
de acuerdo con el método de cálculo que especifique. El elemento y el valor de inicialización se calculan, y el resultado del cálculo se calcula con los siguientes elementos.
El cálculo interno de la forma sobrecargada de los dos parámetros de reduce es el siguiente:

T result = identity;
for(T element : this stream)
    result = accumulator.apply(result,element)
return result;

El método de cálculo interno de la forma sobrecargada de reduce es el siguiente: asigne el primer elemento al valor inicial y luego calcule

boolean foundAny = false;
T result = null;
for (T element : this stream) {
    
    
    if (!foundAny) {
    
    
        foundAny = true;
        result = element;
    }
    else
        result = accumulator.apply(result, element);
}
return foundAny ? Optional.of(result) : Optional.empty();

Entre ellos, la identidad es el valor inicial que podemos pasar a través de los parámetros del método, y qué cálculo se realiza mediante la aplicación del acumulador también lo determinamos a través de los parámetros del método.

//reduce简单理解(模拟)
int[] arr = {
    
    1,2,3,4};
int resut = 0;// 初始值
for (int i : arr){
    
      
    resut = resut + 1;// 具体操作
}
System.out.println(resut);

Ejemplo:
Use reduce para encontrar la suma de edades de todos los autores

//使用reduce求所有作者的年龄和
List<Author> authors = getAuthors();
Integer sum = authors.stream()
    .distinct() // 去重
    .map(author -> author.getAge()) //  获取所有年龄
    // (初始值,(附上初始值,要操作的元素))
    .reduce(0, (result, element) -> result + element);
System.out.println(sum);

Use reduce para encontrar la edad máxima entre los autores

 //使用reduce求所作者中年龄的最大值
 List<Author> authors = getAuthors();
 Integer max = authors.stream()  //其实max() 是封装好的reduce
         .distinct()
         .map(author -> author.getAge()) // 获取年龄
         //      初始值(最小值)      附上初始值,要操作的元素 -> 三目,算出最大值
         .reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);
 System.out.println(max);

Use reduce para encontrar la edad mínima entre todos los autores

//使用reduce求所有作者中年龄的最小值
List<Author> authors = getAuthors();
Integer min = authors.stream()
    .distinct()
    .map(author -> author.getAge())
    //      初始值(最大值)      附上初始值,要操作的元素 -> 三目,算出最小值
    .reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result);

  /*
  Optional<Integer> min = authors.stream().distinct().map(Author::getAge).reduce(Integer::min);
  System.out.println(min);
  */
System.out.println(min);

Use reduce en forma de un parámetro para encontrar la edad mínima entre todos los autores

// reduce一个参数的用法
//使用reduce求所有作者中年龄的最小值
List<Author> authors = getAuthors();
Optional<Integer> minOptional = authors.stream()
    .map(author -> author.getAge())
    //reduce一个参数,把第一个元素赋给初始值
    .reduce((result, element) -> result > element ? element : result);

minOptional.ifPresent(age -> System.out.println(age));

Notas de transmisión

Evaluación diferida (si no hay una operación de finalización, no se ejecutarán operaciones intermedias)
Los flujos son desechables (una vez que un objeto de flujo se somete a una operación de finalización, el flujo no se puede usar de nuevo)
No afecta los datos originales (podemos hacer una mucho procesamiento en los datos de la secuencia, pero en circunstancias normales, no afectará a los elementos de la colección original, que a menudo es lo que esperamos)

Opcional

Descripción general:

Cuando escribimos código, la ocurrencia más común es la excepción de puntero nulo. Entonces, en muchos casos, necesitamos hacer varios juicios no vacíos
, por ejemplo:

List<Author> author = getAuthor();
 if (author != null){
    
    
     System.out.println(author.getName);
 }

·Especialmente cuando las propiedades en el objeto aún no son un objeto. Este tipo de juicio será más
. Demasiadas declaraciones de juicio harán que nuestro código se hinche
. Por lo tanto, Opcional se introdujo en JDK8. Después de que desarrolle el hábito de usar Opcional, puede escribir código más elegante para evitar excepciones de puntero nulo.
·And Optional también se usa en muchas API relacionadas con la programación funcional. Si no sabes cómo usar Optional, también afectará el aprendizaje de la programación funcional.

uso opcional

Crear objeto

Opcional es como una clase contenedora, que puede encapsular nuestros datos específicos dentro de Opcional, y luego podemos usar los métodos encapsulados en Opcional para manipular los datos encapsulados para evitar excepciones de puntero nulo muy elegantemente.

1. Generalmente usamos el método estático opcional de Nullable para encapsular datos en un objeto opcional, sin importar si el parámetro entrante es nulo o no, no habrá ningún problema . enfocar

   Author author = getAuthor();
   Optional<Author> authorOptional = Optional.ofNullable(author);

todo

package com.sangeng;

import java.util.Optional;
import java.util.function.Consumer;

public class OptionalDemo {
    
    
    public static void main(String[] args) {
    
    
        Author author = getAuthor();
        Optional<Author> authorOptional = Optional.ofNullable(author);
        // ifPresent如果存在(如果数据为null,这里是不会被消费的)
        authorOptional.ifPresent(author1 -> System.out.println(author1.getName()));
    }

    public static Author getAuthor(){
    
    
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        return author;// return null;
    }
}

Puede pensar que es problemático agregar una línea de código para encapsular los datos, pero si modificamos el método getAuthor para que su valor de retorno sea el Opcional encapsulado, será mucho más conveniente para nosotros usarlo. (Uso recomendado)

package com.sangeng;

import javax.swing.text.html.Option;
import java.util.Optional;
import java.util.function.Consumer;

public class OptionalDemo {
    
    
    public static void main(String[] args) {
    
    
        Optional<Author> authorOptional = getAuthorOptional();
        authorOptional.ifPresent(author -> System.out.println(author.getName()));
    }

    public static Optional<Author> getAuthorOptional(){
    
    
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        return Optional.ofNullable(author);//直接返回一个Optional
    }
}

Y en el desarrollo real, muchos de nuestros datos se obtienen de la base de datos. Mybatis ha sido compatible con Opcional desde la versión 3.5. Podemos definir directamente el tipo de valor de retorno del método dao como un tipo Opcional, y MyBatis encapsulará los datos en un objeto Opcional y lo devolverá. El proceso de encapsulación no requiere nuestra propia operación.

Si está seguro de que el objeto no está vacío , puede usar el método estático opcional de para encapsular los datos en un objeto opcional (no recomendado
)

 Author author = getAuthor();
 Optional<Author> author1 = Optional.of(author);
package com.sangeng;

import javax.swing.text.html.Option;
import java.util.Optional;
import java.util.function.Consumer;

public class OptionalDemo {
    
    
    public static void main(String[] args) {
    
    

        Author author = getAuthor();
        Optional<Author> author1 = Optional.of(author);
        author1.ifPresent(author2 -> System.out.println(author2.getName()));

    }


    public static Author getAuthor(){
    
    
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        return author;//return null;
    }
}

Debe tenerse en cuenta que si usa de, los parámetros pasados ​​no deben ser nulos. (Intente pasar nulo y qué sucederá)
Use el método of, si los datos están vacíos, se informará una excepción de puntero nulo java.lang.NullPointerException

Si el tipo de valor de retorno de un método es de tipo opcional. Y si juzgamos y encontramos que el valor de retorno de cierto cálculo es nulo, entonces necesitamos encapsular nulo en un objeto Opcional y devolverlo. En este momento, puede usar el método estático opcional vacío para encapsular.

Optional.empty();
public static Optional<Author> getAuthorOptional(){
    
    
    Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
    return author == null?Optional.empty():Optional.of(author);
}

¿Cuál crees que es más conveniente?
Usaré Optional.ofNullable() en el futuro

consumo seguro

Después de obtener un objeto Opcional, definitivamente necesitamos usar los datos que contiene. En este momento, podemos usar su método ifPresent para consumir el valor.Este método juzgará si los datos encapsulados en él están vacíos y solo ejecutará el código de consumo específico cuando no esté vacío. Esto es mucho más seguro de usar.
Por ejemplo,
el siguiente método de escritura evita elegantemente la excepción del puntero nulo.

 Optional<Author> author1 = Optional.of(author);
 author1.ifPresent(author2 -> System.out.println(author2.getName()));

obtener valor

Si queremos obtener el valor y procesarlo nosotros mismos, podemos usar el método get para obtenerlo, pero no es recomendable. Porque ocurre una excepción cuando los datos dentro de Opcional están vacíos.
Usando el método get, si los datos están vacíos, se informará una excepción java.util.NoSuchElementException: No hay valor presente

Optional<Author> author = getAuthorOptional();
Author author1 = author.get();

Obtenga el valor de forma segura

Si esperamos obtener el valor de forma segura. No recomendamos usar el método get, pero use los siguientes métodos proporcionados por Optional.
orElseGet
obtiene datos y establece el valor predeterminado cuando los datos están vacíos. Si los datos no están vacíos, se pueden obtener los datos. Si está vacío, se creará un objeto de acuerdo con los parámetros que ingresó como valor predeterminado .

Optional<Author> authorOptional = getAuthorOptional();
//如果有值,就返回Author。如果没有值就返回默认值orElseGet(设置默认值)
Author author = authorOptional.orElseGet(() -> new Author());
Optional<Author> authorOptional = getAuthorOptional();
//如果有值,就返回Author。如果没有值就返回默认值orElseGet(设置默认值)
Author author = authorOptional.orElseGet(() -> new Author(2L,"大雨",33,"一个从菜刀中明悟哲理的祖安人",null));
System.out.println(author.getName());

public static Optional<Author> getAuthorOptional(){
    
    
    Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
    //Author author = null;
    return author == null?Optional.empty():Optional.of(author);
}

orElseThrow
obtiene los datos, si los datos no están vacíos, se pueden obtener los datos. Si está vacío, se genera una excepción en función de los parámetros que pase .
plantilla de maestro

Optiona1<Author> authoroptiona1 = Optional.ofNu1lable(getAuthor 0));
try {
    
    
    Author author = authoroptional.orElseThrow((Supplier<Throwable>) () ->
                                                new RuntimeException("author为空"));
    System.out .printIn(author .getName());
} catch (Throwable throwable) {
    
    
    throwable.printstackTrace();
};

prueba de combate

Optional<Author> authorOptional = getAuthorOptional();
try {
    
    
    //如果author,就输出author。如果为空,就抛出异常。
    Author author = authorOptional.orElseThrow(() -> new RuntimeException("数据为null"));
    System.out.println(author);
} catch (Throwable throwable) {
    
    
    throwable.printStackTrace();
}

public static Optional<Author> getAuthorOptional(){
    
    
    Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
    //Author author = null;
    return author == null?Optional.empty():Optional.of(author);
}

filtrar

Podemos usar el método de filtro para filtrar los datos. Si hay datos originalmente, pero no cumple con el juicio, también se convertirá en un objeto opcional sin datos.

Optional<Author> authorOptional = getAuthorOptional();
authorOptional.filter(author -> author.getAge() > 18)
    .ifPresent(author -> System.out.println(author.getName()));

public static Optional<Author> getAuthorOptional(){
    
    
    Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
    //Author author = null;
    return author == null?Optional.empty():Optional.of(author);
}

juicio

Podemos usar el método isPresent para juzgar si hay datos. Si está vacío, el valor devuelto es falso, y si no está vacío, el valor devuelto es verdadero. Sin embargo, este método no refleja los beneficios de Optional y se recomienda utilizar el método ifPresent

Optional<Author> authorOptional = getAuthorOptional();
if (authorOptional.isPresent()) {
    
    
    System.out.println(authorOptional.get().getName());
}

conversión de datos

Optional también proporciona un mapa que nos permite convertir los datos, y los datos convertidos todavía están empaquetados por Optional, lo que garantiza nuestro uso seguro. Por ejemplo, queremos obtener la colección de libros de los autores
.

Optional<Author> authorOptional = getAuthorOptional();
authorOptional.map(author -> author.getBooks())
    .ifPresent(books -> System.out.println(books));

Optional<Author> authorOptional = getAuthorOptional();
        Optional<List<Book>> optionalBooks = authorOptional.map(author -> author.getBooks());
        optionalBooks.ifPresent(books -> System.out.println(books));

Resumir

Opcional:ofNullable
Opcional autorOpcional = Opcional.ofNullable(autor);
安全消费:ifPresent
autorOpcional.ifPresent(autor2 -> System.out.println(autor2.getName()));

interfaz funcional

descripción general

Una interfaz con un solo método abstracto se denomina interfaz funcional.
Las interfaces funcionales del JDK están marcadas con anotaciones **@FunctionallInterface**. Pero no importa si la anotación se agrega o no, siempre que solo haya un método abstracto en la interfaz, es una interfaz funcional.

Interfaz funcional común

De acuerdo con la lista de parámetros y el tipo de valor de retorno del método abstracto en la interfaz de consumo del consumidor
, podemos consumir los parámetros entrantes en el método.

@FunctionalInterface
public interface Consumer<T> {
    
    

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    /**
     * Returns a composed {@code Consumer} that performs, in sequence, this
     * operation followed by the {@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {@code after} operation will not be performed.
     *
     * @param after the operation to perform after this operation
     * @return a composed {@code Consumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
    
    
        Objects.requireNonNull(after);
        return (T t) -> {
    
     accept(t); after.accept(t); };
    }

Interfaz de conversión de cálculo de funciones
De acuerdo con la lista de parámetros y el tipo de valor de retorno del método abstracto, podemos calcular o convertir los parámetros entrantes en el método y devolver el resultado

@FunctionalInterface
public interface Function<T, R> {
    
    

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

    /**
     * Returns a composed function that first applies the {@code before}
     * function to its input, and then applies this function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of input to the {@code before} function, and to the
     *           composed function
     * @param before the function to apply before this function is applied
     * @return a composed function that first applies the {@code before}
     * function and then applies this function
     * @throws NullPointerException if before is null
     *
     * @see #andThen(Function)
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
    
    
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

Interfaz de evaluación de predicados
De acuerdo con la lista de parámetros y el tipo de valor devuelto del método abstracto, podemos juzgar las condiciones de los parámetros entrantes en el método y devolver el resultado de la evaluación

@FunctionalInterface
public interface Predicate<T> {
    
    

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * AND of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code false}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ANDed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * AND of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default Predicate<T> and(Predicate<? super T> other) {
    
    
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

Interfaz de producción del proveedor
De acuerdo con la lista de parámetros y el tipo de valor de retorno del método abstracto, podemos crear objetos en el método y devolver el objeto creado

@FunctionalInterface
    public interface Supplier<T> {
    
    

        /**
        * Gets a result.
        *
        * @return a result
        */
        T get();
    }

![imagen.png](https://img-blog.csdnimg.cn/img_convert/b8949435efdda633d4b4c8fbd258902b.png#averageHue=#f3f3dc&clientId=u3b1cbb5a-c114-4&crop=0&crop=0&crop=1&crop=1&from=paste& altura=251&id=ua0206448&margen= [objeto Objeto]&name=image.png&originHeight=282&originWidth=1001&originalType=binary&ratio=1&rotation=0&showTitle=false&size=177121&status=done&style=none&taskId=u70a12f12-cc60-4b11-ba18-a6c487dedb0&title=&width=8 89.7777777777778)

método predeterminado común

Y
cuando usamos la interfaz Predicate, es posible que necesitemos empalmar las condiciones de juicio. El método and es equivalente a usar && para empalmar dos condiciones de juicio
. Por ejemplo:
escritores impresos cuya edad es mayor de 17 años y cuya longitud de nombre es mayor de 1.

//打印作家中年龄大于17并且姓名的长度大于1的作家。
List<Author> authors = getAuthors();
authors.stream()
    .filter(new Predicate<Author>() {
    
    
        @Override
        public boolean test(Author author) {
    
    
            return author.getAge() > 17;
        }
    }.and(new Predicate<Author>() {
    
    
        @Override
        public boolean test(Author author) {
    
    
            return author.getName().length() > 1;
        }
    }))
    .forEach(author -> System.out.println(author));

O
cuando usamos la interfaz Predicate, es posible que necesitemos empalmar las condiciones de juicio. El método o es equivalente a usar para empalmar dos condiciones de juicio.
Por ejemplo:
escritores impresos cuya edad es mayor de 17 años o cuyo nombre tiene menos de 2.

//打印作家中年龄大于17或者姓名的长度小于2的作家。
List<Author> authors = getAuthors();
authors.stream()
    .filter(new Predicate<Author>() {
    
    
        @Override
        public boolean test(Author author) {
    
    
            return author.getAge()>17;
        }
    }.or(new Predicate<Author>() {
    
    
        @Override
        public boolean test(Author author) {
    
    
            return author.getName().length() < 2;
        }
    })).forEach(author -> System.out.println(author.getName()));

negar
el método en la interfaz Predicate. El método de negación es equivalente a agregar un ! antes de la suma del juicio para indicar la negación
Por ejemplo:
escriban en letra de imprenta cuya edad no sea mayor de 17 años.

//打印作家中年龄不大于17的作家。
List<Author> authors = getAuthors();
authors.stream()
    .filter(new Predicate<Author>() {
    
    
        @Override
        public boolean test(Author author) {
    
    
            return author.getAge() > 17;
        }
    }.negate()).forEach(author -> System.out.println(author));

referencia del método

Cuando usamos lambda, si solo hay una llamada de método en el cuerpo del método (incluido el método de construcción), podemos usar referencias de métodos para simplificar aún más el código.

método recomendado

Cuando usamos lambda, no necesitamos considerar cuándo usar referencias de métodos, qué referencias de métodos usar y cuál es el formato de las referencias de métodos. Solo necesitamos usar teclas de método abreviado para probar si se puede convertir en una referencia de método cuando encontramos que el cuerpo del método tiene solo una línea de código después de escribir el método lambda, y es una llamada de método.
Cuando usamos más referencias a métodos, podemos escribir lentamente referencias a métodos directamente.

formato básico

nombre de clase u objeto::nombre de método

Gramática detallada

haciendo referencia a un método estático

De hecho, es el
formato de método estático de la clase de referencia.

类名::方法名

Requisitos previos
Si reescribimos un método, solo hay una línea de código en el cuerpo del método , y esta línea de código llama a un método estático de cierta clase , y pasamos todos los parámetros en el método abstracto para que se reescriban en orden. este método estático , en este momento podemos referirnos al método estático de la clase.
Por ejemplo:
el siguiente código se puede simplificar con referencias de métodos

List<Author> authors = getAuthors();
authors.stream()
    .map(author -> author.getAge())
    .map(age -> String.valueOf(age));

Tenga en cuenta que si el método que reescribimos no tiene parámetros, el método llamado tampoco tiene parámetros, lo que equivale a cumplir con las reglas anteriores.
Después de la optimización es la siguiente:

List<Author> authors = getAuthors();
authors.stream()
    .map(author -> author.getAge())
    .map(String::valueOf);

Método de instancia de objeto de referencia

Formato

对象名::方法名

Requisitos previos
Si reescribimos un método, solo hay una línea de código en el cuerpo del método , y esta línea de código llama a un método miembro de un objeto , y pasamos todos los parámetros en el método abstracto para que se reescriban en orden. método miembro , podemos referirnos al método de instancia del objeto en este momento.Por
ejemplo:

List<Author> authors = getAuthors();
Stream<Author> authorstream = authors .stream();
StringBuilder sb = new StringBuilder();
authorstream.map(author -> author.getName())
    .forEach(name->sb.append(name));

Optimizado:

List<Author> authors = getAuthors();
Stream<Author> authorstream = authors .stream();
StringBuilder sb = new StringBuilder();
authorstream.map(author -> author.getName())
    .forEach(sb::append);

Método de instancia de clase de referencia

Formato

类名::方法名

Si
reescribimos el método, solo hay , y esta línea de código llama al método miembro del primer parámetro , y ponemos todos los parámetros restantes en el método abstracto para reescribirlos. Todos se pasan en este método miembro en orden , y en este momento podemos referirnos al método de instancia de la clase.
Por ejemplo:

package com.sangeng;

import java.util.List;

public class MethodDemo {
    
    
    interface UseString{
    
    
        String use(String str,int start,int length) ;
    }


    public static String subAuthorName(String str, UseString useString) {
    
    
        int start = 0;
        int length = 1;
        return useString.use(str, start, length);

    }
    public static void main(String[] args) {
    
    
        subAuthorName("三更草堂",new UseString() {
    
    
            @Override
            public String use(String str, int start, int length) {
    
    
                return str.substring(start,length);
            }
        });

    }

}

Optimizado:

package com.sangeng;

import java.util.List;

public class MethodDemo {
    
    
    interface UseString{
    
    
        String use(String str,int start,int length) ;
    }


    public static String subAuthorName(String str, UseString useString) {
    
    
        int start = 0;
        int length = 1;
        return useString.use(str, start, length);

    }
    public static void main(String[] args) {
    
    
        subAuthorName("三更草堂", String::substring);

    }

}

referencia del constructor

Las referencias a constructores se pueden usar si una línea de código en el cuerpo del método es un constructor.
Formato

类名::new

Si
reescribimos el método, solo hay una línea de código en el cuerpo del método , y esta línea de código llama al constructor de una determinada clase , y pasamos todos los parámetros en el método abstracto para que se reescriban , podemos referirnos al constructor en este momento.
Por ejemplo:

List<Author> authors = getAuthors();
authors.stream()
    .map(author -> author.getName())
    .map(name -> new StringBuilder(name))
    .map(sb -> sb.append("-三更").toString())
    .forEach(str -> System.out.println(str));

Optimizado:

List<Author> authors = getAuthors();
authors.stream()
    .map(author -> author.getName())
    .map(StringBuilder::new)
    .map(sb -> sb.append("-三更").toString())
    .forEach(str -> System.out.println(str));

uso avanzado

Optimización básica del tipo de datos

Muchos de los métodos Stream que usamos antes usaban genéricos. Entonces, los parámetros involucrados y el valor devuelto son todos tipos de datos de referencia.
Incluso si operamos con enteros y decimales, en realidad usamos sus clases contenedoras. El empaquetado automático y el desempaquetado automático introducidos en JDK5 hacen que sea conveniente para nosotros arreglar y usar tipos de datos básicos cuando usamos las clases de empaquetado correspondientes. Pero debe saber que boxear y desempacar definitivamente consumirá tiempo. Aunque esta vez el consumo es muy bajo. Pero cuando una gran cantidad de datos se empaquetan y abren repetidamente, no puede ignorar esta pérdida de tiempo.
Entonces, para permitirnos optimizar esta parte del consumo de tiempo. Stream también proporciona una serie de métodos específicos para tipos de datos primitivos.

Por ejemplo: madTolnt, mapToLong, mapToDouble, flatMapTolnt, flatMapToDouble, etc.

  List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getAge())
                .map(age -> age +10)
                .filter(age -> age>18)
                .map(age -> age+2)
                .forEach(System.out::println);

        //优化,(自动装箱和拆箱是要消耗时间的)
        authors.stream()
                .mapToInt(author -> author.getAge())// 拆箱一次,Integer->int
                .map(age -> age +10) // 后面的都是int了,不用自动拆箱了。
                .filter(age -> age>18)
                .map(age -> age+2)
                .forEach(System.out::println);

flujo paralelo

Podemos usar secuencias paralelas para mejorar la eficiencia de las operaciones cuando hay una gran cantidad de elementos en la secuencia. De hecho, el flujo paralelo consiste en asignar tareas a múltiples subprocesos para completar. Si usamos el código para implementarlo nosotros mismos, en realidad será muy complicado y requiere que tenga suficiente comprensión y conocimiento de la programación concurrente. Y si usamos Stream, solo necesitamos modificar la llamada de un método para usar flujos paralelos que nos ayuden a lograrlo, mejorando así la eficiencia.

El método paralelo puede convertir un flujo en serie en un flujo paralelo

Stream<Integer> stream = Stream.of(1,2,3,4,5,6,7,8,9,10);
/*
Integer integer = stream.filter(num -> num > 5)
.reduce((result, element) -> result + element)
.get();
System.out.println(integer);
*/

//变成并行流(多线程完成操作)
Integer integer2 = stream.parallel() // parallel并行
    .peek(new Consumer<Integer>() {
    
     // peek调试用的
        @Override
        public void accept(Integer num) {
    
    
            System.out.println(num +Thread.currentThread().getName());//查看是否多线程执行
        }
    })
    .filter(num -> num > 5)
    .reduce((result, element) -> result + element)
    .get();
System.out.println(integer2);

También puede usar el método parallelStream para obtener directamente el objeto de flujo paralelo

List<Author> authors = getAuthors();
authors.parallelStream()	//直接变成并行流

Supongo que te gusta

Origin blog.csdn.net/m0_51315555/article/details/127913909
Recomendado
Clasificación