Лямбда-выражения Java 8 и потоковые операции

Java задняя часть

Синтаксис лямбда-выражения

Основной синтаксис:

(parameters) -> expression
或
(parameters) ->{ statements; }

ссылка на метод

Существует три типа ссылок на методы. Ссылки на методы представлены парой двойных двоеточий ::. Ссылки на методы — это еще один способ написания функционального интерфейса.

  1. Ссылка на статический метод через имя класса::статическое имя метода, например Integer::parseInt
  2. Ссылки на методы экземпляра через InstanceObject::InstanceMethod, например, str::substring
  3. Это также может быть имя класса:: имя метода экземпляра, например String::substring.
  4. Ссылка на конструктор через classname::new, например User::new

Третий момент: если первый параметр списка параметров Lambda является вызывающей стороной метода экземпляра, а второй параметр (или без параметра) является параметром метода экземпляра, формат следующий: имя класса::имя метода экземпляра

There are several basic function shapes,

including Function (unary function from T to R), Consumer (unary function from T to void), Predicate (unary function from T to boolean), and Supplier (nullary function to R).

Function shapes have a natural arity based on how they are most commonly used. The basic shapes can be modified by an arity prefix to indicate a different arity, such as BiFunction (binary function from T and U to R).

Имя класса::имя метода, эквивалентное ссылке на замыкание этого метода, похожее на функцию в js. Например:

public static void main(String[] args) {
        Consumer<String> printStrConsumer = DoubleColon::printStr;
        printStrConsumer.accept("printStrConsumer");
         
        Consumer<DoubleColon> toUpperConsumer = DoubleColon::toUpper;
        toUpperConsumer.accept(new DoubleColon());
         
        BiConsumer<DoubleColon,String> toLowerConsumer = DoubleColon::toLower;
        toLowerConsumer.accept(new DoubleColon(),"toLowerConsumer");
         
        BiFunction<DoubleColon,String,Integer> toIntFunction = DoubleColon::toInt;
        int i = toIntFunction.apply(new DoubleColon(),"toInt");
    }

	static class DoubleColon {
		 
	    public static void printStr(String str) {
	        System.out.println("printStr : " + str);
	    }
	 
	    public void toUpper(){
	        System.out.println("toUpper : " + this.toString());
	    }
	 
	    public void toLower(String str){
	        System.out.println("toLower : " + str);
	    }
	 
	    public int toInt(String str){
	        System.out.println("toInt : " + str);
	        return 1;
	    }
	}

Основное различие между функциями, извлекаемыми с помощью ::, заключается в статических и нестатических методах.Нестатические методы имеют на один параметр больше, чем статические методы, который является вызываемым экземпляром.

// 使用双冒号::来构造非静态函数引用
	    String content = "Hello JDK8";
	    
	    // public String substring(int beginIndex)
	    // 写法一: 对象::非静态方法
	    Function<Integer, String> func = content::substring;
	    String result = func.apply(1);
	    System.out.println(result);
	    
	    // 写法二:
	    IntFunction<String> intFunc = content::substring;
	    result = intFunc.apply(1);
	    System.out.println(result);
	    
	    // 写法三: String::非静态方法
	    BiFunction<String,Integer,String> lala = String::substring;
	    String s = lala.apply(content, 1);
	    System.out.println(s);
	    
	    // public String toUpperCase()
	    // 写法一: 函数引用也是一种函数式接口,所以也可以将函数引用作为方法的参数
	    Function<String, String> func2 = String::toUpperCase;
	    result = func2.apply("lalala");
	    System.out.println(result);
	    
	    // 写法二: 可以改写成Supplier: 入参void, 返回值String
	    Supplier<String> supplier = "alalal"::toUpperCase;
	    result = supplier.get();
	    System.out.println(result);

ссылка на массив

        // 传统Lambda实现
        IntFunction<int[]> function = (i) -> new int[i];
        int[] apply = function.apply(5);
        System.out.println(apply.length); // 5

        // 数组类型引用实现
        function = int[]::new;
        apply = function.apply(10);
        System.out.println(apply.length); // 10

Использование необязательного

c static void main(String[] args) {
    // Optional类已经成为Java 8类库的一部分,在Guava中早就有了,可能Oracle是直接拿来使用了
    // Optional用来解决空指针异常,使代码更加严谨,防止因为空指针NullPointerException对代码造成影响
    String msg = "hello";
    Optional<String> optional = Optional.of(msg);
    // 判断是否有值,不为空
    boolean present = optional.isPresent();
    // 如果有值,则返回值,如果等于空则抛异常
    String value = optional.get();
    // 如果为空,返回else指定的值
    String hi = optional.orElse("hi");
    // 如果值不为空,就执行Lambda表达式
    optional.ifPresent(opt -> System.out.println(opt));

Некоторые операции Stream

Некоторые потоки могут быть преобразованы в коллекции, такие как упомянутый ранее toList, который создает экземпляр класса java.util.List. Конечно, существуют также toSet и toCollection, которые генерируют экземпляры классов Set и Collection соответственно.

final List<String> list = Arrays.asList("jack", "mary", "lucy");
		
		// 过滤 + 输出
		System.out.println("过滤 + 输出: ");
		Stream<String> stream = list.stream();
		stream.filter(item -> !item.equals("zhangsan"))
			.filter(item -> !item.equals("wangwu"))
			.forEach(item -> System.out.println(item));
		
		// 限制为2
		System.out.println("limit(2): ");
		list.stream().limit(2).forEach(System.out::println);
		
		// 排序
		System.out.println("排序: ");
		list.stream().sorted((o1, o2) -> o1.compareTo(o2)).forEach(System.out::println);
		
		// 取出最大值
		System.out.println("max: ");
		String result = list.stream().max((o1, o2) -> o1.compareTo(o2)).orElse("error");
		System.out.println(result);
		
		
		// toList
		System.out.println("toList: ");
		List<Integer> collectList = Stream.of(1, 2, 3, 4)
		        .collect(Collectors.toList());
		System.out.println("collectList: " + collectList);
		// 打印结果
		// collectList: [1, 2, 3, 4]
		
		// toSet
		System.out.println("toSet: ");
		Set<Integer> collectSet = Stream.of(1, 2, 3, 4)
		        .collect(Collectors.toSet());
		System.out.println("collectSet: " + collectSet);
		// 打印结果
		// collectSet: [1, 2, 3, 4]

список для отображения (через поток)

List<Person> list = new ArrayList<>();
		list.add(new Person(1, "mary"));
		list.add(new Person(2, "lucy"));
		
		Map<Integer, Person> map = list.stream().collect(Collectors.toMap(Person::getId, Function.identity()));
		System.out.println(map);
		// 输出: {1=Main3$Person@42f30e0a, 2=Main3$Person@24273305}
		
		Map<Integer, String> map2 = list.stream().collect(Collectors.toMap(Person::getId, Person::getName)); 
		System.out.println(map2);
		// 输出: {1=mary, 2=lucy}

разделить блок данных

image.png

Map<Boolean, List<Integer>> map = Stream.of(1, 2, 3, 4)
	        .collect(Collectors.partitioningBy(item -> item > 2));
		System.out.println(map);

// 输出: {false=[1, 2], true=[3, 4]}

Возвращаемое значение функции может разделить данные только на две группы, то есть истинные и ложные.

группировка блоков данных

Группировка данных — это более естественный способ разделения данных.Вместо разделения данных на истинные и ложные части данные можно сгруппировать с произвольными значениями.

image.png

groupingBy предназначен для группировки всех наборов, а результат после группировки имеет вид Map. Среди них ключевым является тип поля для группировки, например, группировка по типу (пользовательский тип: 1, 2, 3, 4) в классе Ussr, тип типа Integer и тип ключа Карты после группировки является целым числом. И он будет разделен не более чем на четыре группы, поэтому конечным результатом будет Map. Предположим, нам нужна коллекция пользователей типа 1, сначала сгруппированных, например:Map<Integer,List<User>> userMap = allUserList.parallelStream().collect(Collectors.groupingBy(User::getType)); Далее вы можете получить(1) прямо с Карты, например:List<User> userList = userMap.get(1);

Яма между groupingBy и partitioningBy

1. Необходимо отметить следующее: при выполнении get, если ключ не существует в groupingBy, он вернет null, а partitioningBy вернет пустой массив, обратите внимание на пустое значение groupingBy.

2. Эффективность потоковой обработки коллекций не обязательно выше, чем у итераторов, если порядок не требуется, то для параллельной потоковой обработки можно использовать parallelStream.

нить

В Java 1.8 мы можем использовать Stream для достижения этой цели. Здесь мы будем использовать Collectors.joining для сбора значений в Stream, что может удобно получить Stream в строку. Функция объединения принимает три параметра, представляющие разрешение (разделение элементов), префикс и суффикс.

String strJoin = Stream.of("1", "2", "3", "4")
        .collect(Collectors.joining(",", "[", "]"));
System.out.println("strJoin: " + strJoin);
// 打印结果
// strJoin: [1,2,3,4]

Чтение TODO + понимание: сравнение производительности групповой статистики с использованием потока в Java 8 и групповой статистики, реализованной обычной реализациейblog.CSDN.net/Ананасовый лед/…

Ссылаться на

Новые функции JDK1.8 (3): Справочник по методам :: и необязательноblog.CSDN.net/v birds best/Ах…

blog.CSDN.net/IO_field/AR… Подробное объяснение основного синтаксиса Stream в серии Java 8

blog.CSDN.net/V_Axis/Ariti…