java8的 lambda表达式到stream API总结备忘

news2025/1/15 15:19:00

文章目录

  • 1. Lambda 表达式
    • 为什么使用 Lambda 表达式
    • 从匿名类到 Lambda 的转换
    • Lambda 表达式语法
      • 语法格式一:无参,无返回值,Lambda 体只需一条语句
      • 语法格式二:Lambda 需要一个参数
      • 语法格式三:Lambda 只需要一个参数时,参数的小括号可以省略
      • 语法格式四:Lambda 需要两个参数,并且有返回值
      • 语法格式五:当 Lambda 体只有一条语句时,return 与大括号可以省略
      • 语法格式六:多条语句
  • 2. 函数式接口
    • 什么是函数式接口
    • 自定义函数式接口
    • 常用的函数式接口
      • 1. 消费式Consumer<T>
      • 2. 功能式Function<T, R>
      • 3.预测Predicate<T>
      • 4.供给/提供Supplier<T>
  • 3. 方法引用与构造器引用
    • 方法引用
    • 构造器引用
    • 数组引用
  • 4. Stream API
    • 什么是 Stream
    • Stream 的操作三个步骤
      • - 创建 Stream
      • - 中间操作
      • - 终止操作(终端操作)
    • 创建 Stream
      • 由数组创建流
      • 由值创建流
      • 由函数创建流:创建无限流
    • Stream 的中间操作
      • 筛选与切片
        • filter(Predicate p)
        • distinct()
        • limit(long maxSize)
        • skip(long n)
      • 映射
        • map(Function f)
        • mapToDouble(ToDoubleFunction f)
        • mapToInt(ToIntFunction f)
        • mapToLong(ToLongFunction f)
        • flatMap(Function f)
      • 排序
    • Stream 的终止操作
      • 查找与匹配
        • allMatch(Predicate p) 检查是否匹配所有元素
        • anyMatch(Predicate p) 检查是否至少匹配一个元素
        • noneMatch(Predicate p) 检查是否没有匹配所有元素
        • findFirst() 返回第一个元素终端操作会从流的流水线生成结果。
        • findAny() 返回当前流中的任意元素
      • 归约
        • count() |返回流中元素总数
        • max(Comparator c) 返回流中最大值
        • min(Comparator c)返回流中最小值
        • forEach(Consumer c) 内部迭代
        • reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T
      • 收集
        • 1、toList
        • 2、toMap
        • 3、toSet
        • 4、counting
        • 5、summingInt
        • 6、minBy
        • 7、joining
        • 8、groupingBy
        • 1.orElse(null)
        • 2.orElseGet(null)
        • orElse(null)和orElseGet(null)区别:
    • 并行流和串行流
  • 5. 新时间日期 API
    • 使用 LocalDate、LocalTime、LocalDateTime
  • 6. java8其他新特性

1. Lambda 表达式

为什么使用 Lambda 表达式

Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更 灵活的代码。作为一种更紧凑的代码风格,使 Java的语言表达能力得到了提升。

从匿名类到 Lambda 的转换

	//原来的匿名内部类
	@Test
	public void test1(){
		Comparator<String> com = new Comparator<String>(){
			@Override
			public int compare(String o1, String o2) {
				return Integer.compare(o1.length(), o2.length());
			}
		};
		
		TreeSet<String> ts = new TreeSet<>(com);
		
		TreeSet<String> ts2 = new TreeSet<>(new Comparator<String>(){
			@Override
			public int compare(String o1, String o2) {
				return Integer.compare(o1.length(), o2.length());
			}
			
		});
	}
	
	//现在的 Lambda 表达式
	@Test
	public void test2(){
		Comparator<String> com = (x, y) -> Integer.compare(x.length(), y.length());
		TreeSet<String> ts = new TreeSet<>(com);
	}
	
	List<Employee> emps = Arrays.asList(
			new Employee(101, "张三", 18, 9999.99),
			new Employee(102, "李四", 59, 6666.66),
			new Employee(103, "王五", 28, 3333.33),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(105, "田七", 38, 5555.55)
	);

Lambda 表达式语法

Lambda 表达式在Java 语言中引入了一个新的语法元
素和操作符。这个操作符为 “->” , 该操作符被称
为 Lambda 操作符或剪头操作符。它将 Lambda 分为
两个部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行
的功能。

语法格式一:无参,无返回值,Lambda 体只需一条语句

 // 语法格式一:无参数,无返回值
	@Test
	public void test1(){
		int num = 0; 
		
		Runnable r = new Runnable() {
			@Override
			public void run() {
				System.out.println("Hello World!" + num);
			}
		};
		
		r.run();
		
		System.out.println("-------------------------------");
		
		Runnable r1 = () -> System.out.println("Hello Lambda!");
		r1.run();
	}

语法格式二:Lambda 需要一个参数

Consumer<String> con = (x) -> System.out.println(x);

语法格式三:Lambda 只需要一个参数时,参数的小括号可以省略

Consumer<String> con = x -> System.out.println(x);

语法格式四:Lambda 需要两个参数,并且有返回值

Comparator<Integer> com = (x, y) -> {
			System.out.println("函数式接口");
			return Integer.compare(x, y);
}

语法格式五:当 Lambda 体只有一条语句时,return 与大括号可以省略

Consumer<String> con = (x,y) -> x + y;

语法格式六:多条语句

Comparator<Integer> com = (x, y) -> {
			System.out.println("函数式接口");
			return Integer.compare(x, y);
}

2. 函数式接口

什么是函数式接口

  • 只包含一个抽象方法的接口,称为函数式接口。
  • 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda
    表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方
    法上进行声明)。
  • 我们可以在任意函数式接口上使用 @FunctionalInterface 注解,
    这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包
    含一条声明,说明这个接口是一个函数式接口。

自定义函数式接口

@FunctionalInterface
public interface MyNumberf{
	public double getValue();
}
//函数式接口中使用泛型:
public interface MyFunc<T>{
	public T getValue(T t);
}

@FunctionalInterface
public interface MyFunction {
    int apply(int x, int y);
}

MyFunction add = (x, y) -> x + y;
int result = add.apply(5, 3);
System.out.println(result); // 输出8

MyFunction multiply = (x, y) -> x * y;
result = multiply.apply(5, 3);
System.out.println(result); // 输出15

常用的函数式接口

1. 消费式Consumer

  • 源码解析
@FunctionalInterface
public interface Consumer<T> {

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

    /**
     * andThen()方法用于将两个Consumer对象串联起来,实现多个操作的
     * 连续执行。该方法的语法格式为consumer1.andThen(consumer2),
     * 其中consumer1和consumer2分别为两个Consumer对象。
     * 
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

  • 使用实例
Consumer<String> consumer1 = s -> System.out.println("consumer1: " + s);
Consumer<String> consumer2 = s -> System.out.println("consumer2: " + s);
Consumer<String> consumer3 = consumer1.andThen(consumer2);

consumer3.accept("hello world");


输出:

consumer1: hello world
consumer2: hello world

2. 功能式Function<T, R>

  • 源码解析
@FunctionalInterface
public interface Function<T, R> {

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

    /**
     * compose()方法用于将两个Function对象串联起来,实现多个操作
     * 的连续执行,并返回一个新的Function对象。该方法的语法格式为
     * function1.compose(function2),其中function1和function2分别
     * 为两个Function对象。
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    /**
     * andThen()方法与compose()方法类似,但它先执行当前Function对象
     * 的操作,再执行参数Function对象的操作,并返回一个新的
     * Function对象。该方法的语法格式为function1.andThen(function2)
     * ,其中function1和function2分别为两个Function对象。
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /**
     * identity()方法是一个静态方法,返回一个恒等函数,即输入参数和
     * 输出结果都相同的函数。该方法的语法格式为Function.identity()
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
  • 使用实例
Function<Integer, Integer> function1 = x -> x + 1;
Function<Integer, Integer> function2 = x -> x * 2;
Function<Integer, Integer> function3 = function1.compose(function2);

int result3 = function3.apply(5);
System.out.println(result3); // 输出11

Function<Integer, Integer> function4 = function1.andThen(function2);

int result4 = function4.apply(5);
System.out.println(result4); // 输出12

Function<String, String> function = Function.identity();
String str = function.apply("hello");
System.out.println(str); // 输出hello


输出:

11
12
hello

3.预测Predicate

  • 源码解析
@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     */
    boolean test(T t);

    /**
     * and()方法用于将两个Predicate对象组合起来,并返回一个新的Predicate对象,
     * 实现多个条件的同时满足。该方法的语法格式为predicate1.and(predicate2),
     * 其中predicate1和predicate2分别为两个Predicate对象。
     */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    /**
     * negate()方法用于对Predicate对象进行取反操作,并返回一个新的Predicate对象。
     * 该方法的语法格式为predicate.negate(),其中predicate为原始的Predicate对象
     */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    /**
     * or()方法与and()方法类似,但它实现多个条件的任意一个满足即可。该方法的语法格式为predicate1.or(predicate2),
     * 其中predicate1和predicate2分别为两个Predicate对象。
     */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    /**
     * 
     */
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

  • 使用实例
Predicate<String> predicate1 = s -> s.startsWith("hello");
Predicate<String> predicate2 = s -> s.endsWith("world");
Predicate<String> predicate3 = predicate1.and(predicate2);
boolean result3 = predicate3.test("hello world");
System.out.println(result3); // 输出true
Predicate<String> predicate4 = predicate1.or(predicate2);
boolean result4 = predicate4.test("hello world");
System.out.println(result4); // 输出false
Predicate<String> negatedPredicate = predicate1.negate();
boolean result = negatedPredicate.test("hello world");
System.out.println(result); // 输出false
Predicate<String> predicate = Predicate.isEqual("hello world");
boolean result1 = predicate.test("hello world");
boolean result2 = predicate.test("hello java");
System.out.println(result1); // 输出true
System.out.println(result2); // 输出false

4.供给/提供Supplier

  • 源码解析
@FunctionalInterface
public interface Supplier<T> {

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

  • 使用实例
Supplier<Double> supplier = Math::random;
double value = supplier.get();

3. 方法引用与构造器引用

方法引用

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!)方法引用:使用操作符“::”
将方法名和对象或类的名字分隔开来。 如下三种主要使用情况:

  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法
(x) -> System.out.println(x);
//等同于
System::println;

构造器引用

格式: ClassName::new
与函数式接口相结合,自动与函数式接口中方法兼容。
可以把构造器引用赋值给定义的方法,与构造器参数
列表要与接口中抽象方法的参数列表一致!

Function<Integer,MyClass> func = (n) -> new MyClass(n);
//等同于
Function<Integer,MyClass> func1 = MyClass::new;

数组引用

格式: type[] :: new

Function<Integer,Integer[]> func = (n) -> new Integer[n];
Function<Integer,Integer[]> func = Integer[]::new;

4. Stream API

Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一
个则是 Stream API(java.util.stream.*)。
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对
集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。
使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数
据库查询。也可以使用 Stream API 来并行执行操作。简而言之,
Stream API 提供了一种高效且易于使用的处理数据的方式。

什么是 Stream

流(Stream) 到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

“集合讲的是数据,流讲的是计算

注意:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

Stream 的操作三个步骤

- 创建 Stream

一个数据源(如:集合、数组),获取一个流

- 中间操作

一个中间操作链,对数据源的数据进行处理

- 终止操作(终端操作)

一个终止操作,执行中间操作链,并产生结果

在这里插入图片描述

创建 Stream

  • default Stream stream() : 返回一个顺序流
  • default Stream parallelStream() : 返回一个并行流

由数组创建流

Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:

static Stream stream(T[] array): 返回一个流
重载形式,能够处理对应基本类型的数组:
 public static IntStream stream(int[] array)
 public static LongStream stream(long[] array)
 public static DoubleStream stream(double[] array)

由值创建流

可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。
public static<T> Stream<T> of(T... values) //: 返回一个流

由函数创建流:创建无限流

可以使用静态方法 Stream.iterate() 和Stream.generate(), 创建无限流。
  • 迭代
    public static Stream iterate(final T seed, final
    UnaryOperator f)
  • 生成
    public static Stream generate(Supplier s) :

Stream 的中间操作

多个中间操作可以连接起来形成一个流水线,除非流水 线上触发终止操作,否则中间操作不会执行任何的处理!
而在终止操作时一次性全部处理,称为“惰性求值”。

筛选与切片

方法描述
filter(Predicate p)接收 Lambda , 从流中排除某些元素。
distinct()筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
limit(long maxSize)截断流,使其元素不超过给定数量。
skip(long n)跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n)互补
filter(Predicate p)
distinct()
limit(long maxSize)
skip(long n)
package com.lyzdfintech.loongeasy.testengine;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

public class TestFort {
    public static void main(String[] args) {
        List<User> userList = getUserList();
        System.out.println(userList);

        System.out.println("=======================filter=========================");
        //1、filter:输出ID大于6的user对象
        List<User> filetrUserList = userList.stream().filter(user -> user.getId() > 6).collect(Collectors.toList());
        filetrUserList.forEach(System.out::println);
        System.out.println("=======================distinct=========================");
        //2、distinct:去重
        List<String> distinctUsers =  userList.stream().map(User::getCity).distinct().collect(Collectors.toList());
        distinctUsers.forEach(System.out::println);
        System.out.println("=======================limit=========================");
        //3、limit:取前5条数据
        userList.stream().limit(5).collect(Collectors.toList()).forEach(System.out::println);
        System.out.println("=======================skip=========================");
        //4、skip:跳过第几条取后几条
        userList.stream().skip(7).collect(Collectors.toList()).forEach(System.out::println);
    }

    private static List<User> getUserList() {
        List<User> userList = new ArrayList<>();

        userList.add(new User(1, "张三", 18, "上海"));
        userList.add(new User(2, "王五", 16, "上海"));
        userList.add(new User(3, "李四", 20, "上海"));
        userList.add(new User(4, "张雷", 22, "北京"));
        userList.add(new User(5, "张超", 15, "深圳"));
        userList.add(new User(6, "李雷", 24, "北京"));
        userList.add(new User(7, "王爷", 21, "上海"));
        userList.add(new User(8, "张三丰", 18, "广州"));
        userList.add(new User(9, "赵六", 16, "广州"));
        userList.add(new User(10, "赵无极", 26, "深圳"));

        return userList;
    }

}

@Data
@AllArgsConstructor
class User {
    int id;
    String name;
    int age;
    String city;


}

映射

方 法描 述
map(Function f)接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
mapToDouble(ToDoubleFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
mapToInt(ToIntFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。
mapToLong(ToLongFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。
flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
map(Function f)
mapToDouble(ToDoubleFunction f)
mapToInt(ToIntFunction f)
mapToLong(ToLongFunction f)
flatMap(Function f)
package com.lyzdfintech.loongeasy.testengine;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;

public class TestFort {
    public static void main(String[] args) {
        List<User> userList = getUserList();
        System.out.println(userList);

        System.out.println("=======================map=========================");
        //1、map
        List<String> mapUserList = userList.stream().map(user -> user.getName() + "用户").collect(Collectors.toList());
        mapUserList.forEach(System.out::println);
        System.out.println("=======================mapToDouble=========================");
        //2、mapToDouble
        DoubleStream mapToDoubleList = userList.stream().map(user -> user.getAge()).mapToDouble(x ->x.doubleValue());
        mapToDoubleList.forEach(System.out::println);

        /*3、flatMap:数据拆分一对多映射
         *使用flatMap方法的效果是,各个数组并不是分别映射成一个流,而是映射成流的内容。所有使用map(Arrays::stream)时生成的单个流都被合并起来,即扁平化为一个流
         */
        userList.stream().flatMap(user -> Arrays.stream(user.getCity().split(","))).forEach(System.out::println);


    }

    private static List<User> getUserList() {
        List<User> userList = new ArrayList<>();

        userList.add(new User(1, "张三", 18, "上海"));
        userList.add(new User(2, "王五", 16, "上海"));
        userList.add(new User(3, "李四", 20, "上海"));
        userList.add(new User(4, "张雷", 22, "北京"));
        userList.add(new User(5, "张超", 15, "深圳"));
        userList.add(new User(6, "李雷", 24, "北京"));
        userList.add(new User(7, "王爷", 21, "上海"));
        userList.add(new User(8, "张三丰", 18, "广州"));
        userList.add(new User(9, "赵六", 16, "广州"));
        userList.add(new User(10, "赵无极", 26, "深圳"));

        return userList;
    }

}

@Data
@AllArgsConstructor
class User {
    int id;
    String name;
    int age;
    String city;


}

排序

方 法描 述
sorted()产生一个新流,其中按自然顺序排序
sorted(Comparator comp)产生一个新流,其中按比较器顺序排序
package com.lyzdfintech.loongeasy.testengine;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;

public class TestFort {
    public static void main(String[] args) {
        List<User> userList = getUserList();
        System.out.println(userList);

        System.out.println("=======================sorted-com=========================");
        //1、sorted:排序,根据id倒序
        userList.stream().sorted(Comparator.comparing(User::getId).reversed()).collect(Collectors.toList()).forEach(System.out::println);
        System.out.println("=======================sorted=========================");
        userList.stream().sorted().collect(Collectors.toList()).forEach(System.out::println);
    }

    private static List<User> getUserList() {
        List<User> userList = new ArrayList<>();

        userList.add(new User(1, "张三", 18, "上海"));
        userList.add(new User(2, "王五", 16, "上海"));
        userList.add(new User(3, "李四", 20, "上海"));
        userList.add(new User(4, "张雷", 22, "北京"));
        userList.add(new User(5, "张超", 15, "深圳"));
        userList.add(new User(6, "李雷", 24, "北京"));
        userList.add(new User(7, "王爷", 21, "上海"));
        userList.add(new User(8, "张三丰", 18, "广州"));
        userList.add(new User(9, "赵六", 16, "广州"));
        userList.add(new User(10, "赵无极", 26, "深圳"));

        return userList;
    }

}

@Data
@AllArgsConstructor
class User {
    int id;
    String name;
    int age;
    String city;


}

Stream 的终止操作

查找与匹配

方 法描 述
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有元素
findFirst()返回第一个元素终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。
findAny()返回当前流中的任意元素
allMatch(Predicate p) 检查是否匹配所有元素
anyMatch(Predicate p) 检查是否至少匹配一个元素
noneMatch(Predicate p) 检查是否没有匹配所有元素
findFirst() 返回第一个元素终端操作会从流的流水线生成结果。
findAny() 返回当前流中的任意元素
package com.lyzdfintech.loongeasy.testengine;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;

public class TestFort {
    public static void main(String[] args) {
        List<User> userList = getUserList();
        System.out.println(userList);

        System.out.println("=======================matchAll + anyMatch + noneMatch=========================");
        //1、allMatch:检查是否匹配所有元素
        boolean matchAll = userList.stream().allMatch(user -> "北京".equals(user.getCity()));
        System.out.println("matchAll :" + matchAll);
        //2、anyMatch:检查是否至少匹配一个元素
        boolean matchAny = userList.stream().anyMatch(user -> "北京".equals(user.getCity()));
        System.out.println("anyMatch :" + matchAny);
        //3、noneMatch:检查是否没有匹配所有元素,返回boolean
        boolean nonaMatch = userList.stream().noneMatch(user -> "云南".equals(user.getCity()));
        System.out.println("noneMatch :" + nonaMatch);

        //4、findFirst:返回第一个元素
        User firstUser = userList.stream().findFirst().get();
        User firstUser1 = userList.stream().filter(user -> "上海".equals(user.getCity())).findFirst().get();
        System.out.println("firstUser :" + firstUser + ";" + "firstUser1 :" + firstUser1);
        //5、findAny:将返回当前流中的任意元素
        User findUser = userList.stream().findAny().get();
        User findUser1 = userList.stream().filter(user -> "上海".equals(user.getCity())).findAny().get();
        System.out.println("findUser :" + findUser + ";" + "findUser1 :" + findUser1);

    }

    private static List<User> getUserList() {
        List<User> userList = new ArrayList<>();

        userList.add(new User(1, "张三", 18, "上海"));
        userList.add(new User(2, "王五", 16, "上海"));
        userList.add(new User(3, "李四", 20, "上海"));
        userList.add(new User(4, "张雷", 22, "北京"));
        userList.add(new User(5, "张超", 15, "深圳"));
        userList.add(new User(6, "李雷", 24, "北京"));
        userList.add(new User(7, "王爷", 21, "上海"));
        userList.add(new User(8, "张三丰", 18, "广州"));
        userList.add(new User(9, "赵六", 16, "广州"));
        userList.add(new User(10, "赵无极", 26, "深圳"));

        return userList;
    }

}

@Data
@AllArgsConstructor
class User {
    int id;
    String name;
    int age;
    String city;


}

归约

方 法描 述
count()返回流中元素总数
max(Comparator c)返回流中最大值
min(Comparator c)返回流中最小值
forEach(Consumer c)内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)
reduce(T iden, BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回 T
reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回 Optional
count() |返回流中元素总数
max(Comparator c) 返回流中最大值
min(Comparator c)返回流中最小值
forEach(Consumer c) 内部迭代
reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T
package com.lyzdfintech.loongeasy.testengine;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Setter;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;

public class TestFort {
    public static void main(String[] args) {
        List<User> userList = getUserList();
        System.out.println(userList);

        System.out.println("=======================归约=========================");

        //1、count:返回流中元素总数
        long count = userList.stream().filter(user -> user.getAge() > 20).count();
        System.out.println("count : " + count);

        //2、max:最大值
        int max = userList.stream().max(Comparator.comparingInt(User::getId)).get().getId();
        System.out.println("max id : " + max);

        //3、min:最小值
        int min = userList.stream().min(Comparator.comparingInt(User::getId)).get().getId();
        System.out.println("min id : " + min);

        //4、forEach:遍历流
        userList.stream().forEach(user -> System.out.println(user));
        userList.stream().filter(user -> "上海".equals(user.getCity())).forEach(System.out::println);
        System.out.println("reduce:");
        //5、reduce:将流中元素反复结合起来,得到一个值
        Optional reduce = userList.stream().reduce((user, user2) -> {
            user.name = user.name + user2.name;
            return user;
        });
        if(reduce.isPresent()) System.out.println(reduce.get());

    }

    private static List<User> getUserList() {
        List<User> userList = new ArrayList<>();

        userList.add(new User(1, "张三", 18, "上海"));
        userList.add(new User(2, "王五", 16, "上海"));
        userList.add(new User(3, "李四", 20, "上海"));
        userList.add(new User(4, "张雷", 22, "北京"));
        userList.add(new User(5, "张超", 15, "深圳"));
        userList.add(new User(6, "李雷", 24, "北京"));
        userList.add(new User(7, "王爷", 21, "上海"));
        userList.add(new User(8, "张三丰", 18, "广州"));
        userList.add(new User(9, "赵六", 16, "广州"));
        userList.add(new User(10, "赵无极", 26, "深圳"));

        return userList;
    }

}

@Data
@AllArgsConstructor
class User {
    int id;
    String name;
    int age;
    String city;


}

收集

方 法描 述
collect(Collector c)将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法

Collector 接口中方法的实现决定了如何对流执行收集操作(如收 集到 List、Set、Map)。但是 Collectors实用类提供了很多静态 方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

方法返回类型作用
toListList把流中元素收集到List
List emps= list.stream().collect(Collectors.toList());
toSetSet把流中元素收集到Set
Set emps= list.stream().collect(Collectors.toSet());
toCollectionCollection把流中元素收集到创建的集合
Collectionemps=list.stream().collect(Collectors.toCollection(ArrayList::new));
countingLong计算流中元素的个数
long count = list.stream().collect(Collectors.counting());
summingIntInteger对流中元素的整数属性求和
inttotal=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingIntDouble计算流中元素Integer属性的平均值
doubleavg= list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingIntIntSummaryStatistics收集流中Integer属性的统计值。如:平均值
IntSummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
joiningString连接流中每个字符串
String str= list.stream().map(Employee::getName).collect(Collectors.joining());
maxByOptional根据比较器选择最大值
Optionalmax= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
minByOptional根据比较器选择最小值
Optional min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
reducing归约产生的类型从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值
inttotal=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));
collectingAndThen转换函数返回的类型包裹另一个收集器,对其结果转换函数
inthow= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
groupingByMap<K, List>根据某属性值对流分组,属性为K,结果为V
Map<Emp.Status, List> map= list.stream().collect(Collectors.groupingBy(Employee::getStatus));
partitioningByMap<Boolean, List>根据true或false进行分区
Map<Boolean,List>vd= list.stream().collect(Collectors.partitioningBy(Employee::getManage));

Collector:结果收集策略的核心接口,具备将指定元素累加存放到结果容器中的能力;并在Collectors工具中提供了Collector接口的实现类

1、toList

将用户ID存放到List集合中

        //1.toList
        List<Integer> idList = userList.stream().map(User::getId).collect(Collectors.toList());
        System.out.println(idList);
2、toMap
        //2.toMap  id name 以key value形式保存
        Map<Integer,String> userMap = userList.stream().collect(Collectors.toMap(User::getId,User::getName));
        System.out.println(userMap);
3、toSet
        //3.toSet
        Set<String> userCitySet = userList.stream().map(user -> user.getCity()).collect(Collectors.toSet());
        System.out.println(userCitySet);

4、counting

符合条件的用户总数

long count = userList.stream().filter(user -> user.getId()>1).collect(Collectors.counting());

5、summingInt

对结果元素即用户ID求和

Integer sumInt = userList.stream().filter(user -> user.getId()>2).collect(Collectors.summingInt(User::getId)) ;

6、minBy

筛选元素中ID最小的用户

User maxId = userList.stream().collect(Collectors.minBy(Comparator.comparingInt(User::getId))).get() ;

7、joining

将用户所在城市,以指定分隔符链接成字符串;

String joinCity = userList.stream().map(User::getCity).collect(Collectors.joining("||"));

8、groupingBy

按条件分组,以城市对用户进行分组;

Map<String,List<User>> groupCity = userList.stream().collect(Collectors.groupingBy(User::getCity));
1.orElse(null)

表示如果一个都没找到返回null(orElse()中可以塞默认值。如果找不到就会返回orElse中设置的默认值)

 
    /**
     * Return the value if present, otherwise return {@code other}.
     *
     * @param other the value to be returned if there is no value present, may
     * be null
     * @return the value, if present, otherwise {@code other}
     * 返回值,如果存在,否则返回其他
     */
    public T orElse(T other) {
        return value != null ? value : other;
    }
2.orElseGet(null)

表示如果一个都没找到返回null(orElseGet()中可以塞默认值。如果找不到就会返回orElseGet中设置的默认值)
orElse() 接受类型T的 任何参数,而orElseGet()接受类型为Supplier的函数接口,该接口返回类型为T的对象

 
    /**
     * Return the value if present, otherwise invoke {@code other} and return
     * the result of that invocation.
     *
     * @param other a {@code Supplier} whose result is returned if no value
     * is present
     * @return the value if present otherwise the result of {@code other.get()}
     * @throws NullPointerException if value is not present and {@code other} is
     * null
     * 返回值如果存在,否则调用其他值并返回该调用的结果
     */
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }
orElse(null)和orElseGet(null)区别:

1、当返回Optional的值是空值null时,无论orElse还是orElseGet都会执行

2、而当返回的Optional有值时,orElse会执行,而orElseGet不会执行

package com.lyzdfintech.loongeasy.testengine;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
 
public class TestStream {
    public static void main(String[] args) {
        List<UserP> list = new ArrayList<>();
 
        //定义三个用户对象
        UserP UserP1 = new UserP();
        UserP1.setUserName("admin");
        UserP1.setAge(16);
        UserP1.setSex("男");
 
        UserP UserP2 = new UserP();
        UserP2.setUserName("root");
        UserP2.setAge(20);
        UserP2.setSex("女");
 
        UserP UserP3 = new UserP();
        UserP3.setUserName("admin");
        UserP3.setAge(18);
        UserP3.setSex("男");
 
        UserP UserP4 = new UserP();
        UserP4.setUserName("admin11");
        UserP4.setAge(22);
        UserP4.setSex("女");
 
        //添加用户到集合中
        list.add(UserP1);
        list.add(UserP2);
        list.add(UserP3);
        list.add(UserP4);
 
        /*
        在集合中查询用户名包含admin的集合
        */
        List<UserP> UserPList = list.stream().filter(UserP -> UserP.getUserName().contains("admin")
                            && UserP.getAge() <= 20).collect(Collectors.toList());
        System.out.println(UserPList);
 
        /*
        在集合中查询出第一个用户名为admin的用户
        */
        Optional<UserP> UserP = list.stream().filter(UserPTemp -> "admin".equals(UserPTemp.getUserName())).findFirst();
        System.out.println(UserP);
 
        /*
        orElse(null)表示如果一个都没找到返回null(orElse()中可以塞默认值。如果找不到就会返回orElse中设置的默认值)
        orElseGet(null)表示如果一个都没找到返回null(orElseGet()中可以塞默认值。如果找不到就会返回orElseGet中设置的默认值)
        orElse()和orElseGet()区别:在使用方法时,即使没有值 也会执行 orElse 内的方法, 而 orElseGet则不会
        */
        //没值
        UserP a =  list.stream().filter(UserPT-> UserPT.getAge() == 12).findFirst().orElse(getMethod("a"));
        UserP b =  list.stream().filter(UserPT11-> UserPT11.getAge() == 12).findFirst().orElseGet(()->getMethod("b"));
        //有值
        UserP c =  list.stream().filter(UserPT2-> UserPT2.getAge() == 16).findFirst().orElse(getMethod("c"));
        UserP d =  list.stream().filter(UserPT22-> UserPT22.getAge() == 16).findFirst().orElseGet(()->getMethod("d"));
        System.out.println("a:"+a);
        System.out.println("b:"+b);
        System.out.println("c:"+c);
        System.out.println("d:"+d);
    }
 
    public static UserP getMethod(String name){
        System.out.println(name + "执行了方法");
 
        return null;
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Setter
class UserP{
    String userName;
    int age;
    String sex;
}

[UserP(userName=admin, age=16, sex=男), UserP(userName=admin, age=18, sex=男)]
Optional[UserP(userName=admin, age=16, sex=男)]
a执行了方法
b执行了方法
c执行了方法
a:null
b:null
c:UserP(userName=admin, age=16, sex=男)
d:UserP(userName=admin, age=16, sex=男)
Process finished with exit code 0

并行流和串行流

并行流就是把一个内容分成多个数据块,并用不同的线程分
别处理每个数据块的流。
Java 8 中将并行进行了优化,我们可以很容易的对数据进行并
行操作。Stream API 可以声明性地通过 parallel() 与
sequential() 在并行流与顺序流之间进行切换。

5. 新时间日期 API

使用 LocalDate、LocalTime、LocalDateTime

LocalDate、LocalTime、LocalDateTime 类的实 例是不可变的对象,分别表示使用 ISO-8601日
历系统的日期、时间、日期和时间。它们提供 了简单的日期或时间,并不包含当前的时间信 息。也不包含与时区相关的信息。

方法描述示例
now()静态方法,根据当前时间创建对象LocalDate localDate = LocalDate.now();LocalTime localTime = LocalTime.now();LocalDateTime localDateTime = LocalDateTime.now();
of()静态方法,根据指定日期/时间创建对象LocalDate localDate = LocalDate.of(2016, 10, 26);LocalTime localTime = LocalTime.of(02, 22, 56);LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55);
plusDays, plusWeeks,plusMonths, plusYears向当前 LocalDate 对象添加几天、几周、几个月、几年
minusDays, minusWeeks,minusMonths, minusYears从当前 LocalDate 对象减去几天、几周、几个月、几年
plus, minus添加或减少一个 Duration 或 Period
withDayOfMonth,withDayOfYear,withMonth,withYear将月份天数、年份天数、月份、年份 修 改 为 指 定 的 值 并 返 回 新 的LocalDate 对象
getDayOfMonth获得月份天数(1-31),getDayOfYear 获得年份天数(1-366),getDayOfWeek 获得星期几(返回一个DayOfWeek枚举值)
getMonth获得月份, 返回一个 Month 枚举值
getMonthValue获得月份(1-12)
getYear获得年份
until获得两个日期之间的 Period 对象,或者指定 ChronoUnits 的数字
isBefore, isAfter比较两个 LocalDate
isLeapYear判断是否是闰年

6. java8其他新特性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1458989.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在iStoreOS软路由系统中安装cpolar实现公网远程本地电脑桌面

文章目录 简介一、配置远程桌面公网地址二、家中使用永久固定地址 访问公司电脑**具体操作方法是&#xff1a;** 简介 软路由是PC的硬件加上路由系统来实现路由器的功能&#xff0c;也可以说是使用软件达成路由功能的路由器。 使用软路由控制局域网内计算机的好处&#xff1a…

微信商户平台:如何查看超级管理员

如果有普通员工身份&#xff0c;可以登录 https://pay.weixin.qq.com/index.php/core/account/info 扫码进入后&#xff0c;进入菜单&#xff1a;账户中心》商户信息&#xff0c; 即可看到超级管理员的信息。

感觉我国的程序员前景一片灰暗,是这样吗?

程序员也分为好几等&#xff0c;在现在看来大部分的Android、Java、前端等等开发。已经看不到希望了&#xff0c;很多人都在边缘挣扎&#xff1b;刚看到一位Android开发者&#xff0c;过完年回公司就通知被裁&#xff1b;可见每年都会有很多互联网公司倒闭&#xff0c;或者裁员…

海鹰数据:Shopee卖家的利器,助力选品决策

在如今激烈竞争的电商市场中&#xff0c;Shopee作为一家备受欢迎的在线购物平台&#xff0c;吸引了大量卖家加入平台进行销售。然而&#xff0c;要在这个竞争激烈的市场中脱颖而出&#xff0c;并非易事。因此&#xff0c;对于Shopee卖家来说&#xff0c;如何科学合理地进行选品…

Milvus数据库介绍

参考&#xff1a;https://www.xjx100.cn/news/1726910.html?actiononClick Milvus 基于FAISS、Annoy、HNSW 等向量搜索库构建&#xff0c;核心是解决稠密向量相似度检索的问题。在向量检索库的基础上&#xff0c;Milvus 支持数据分区分片、数据持久化、增量数据摄取、标量向量…

C++ 区间合并 算法(详解) + 例题

1、定义 把所有&#xff0c;有交集的区间合并 图解&#xff1a; 2、实现 步骤如下&#xff1a; 1、首先按照每个区间左端点排序 2、扫描 所有区间&#xff0c;进行区间合并 上述第二条&#xff0c;可以理解为&#xff1a;拿出一个区间去跟它后面的所有的区间去进行合并&…

面试经典150题——矩阵置零

​"Dream it. Wish it. Do it." - Unknown 1. 题目描述 2. 题目分析与解析 2.1 思路一——暴力求解 思路一很简单&#xff0c;就是尝试遍历矩阵的所有元素&#xff0c;如果发现值等于0&#xff0c;就把当前行与当前列的值分别置为0。同时我们需要注意&#xff0c;…

如何使用安卓平板远程Ubuntu服务器通过VS Code远程开发

文章目录 1.ubuntu本地安装code-server2. 安装cpolar内网穿透3. 创建隧道映射本地端口4. 安卓平板测试访问5.固定域名公网地址6.结语 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&#xff0c;风趣幽默&#xff0c;…

IDEA连接database数据库

文章目录 一、连接数据库1、连接mysql2、连接参数配置3、配置驱动从maven仓库下载&#xff1a;要求联网将提前下载好的jar放到本地目录 4、完成 二、执行sql1、选择要操作的数据库2、执行sql 三、问题1、可能因为时区问题连接不上 一、连接数据库 1、连接mysql 2、连接参数配置…

初始回溯算法

回溯算法一般用于对数据枚举后选取符合条件的结果并最终返回结果集的问题&#xff0c;之所以叫回溯法&#xff0c;是因为它可进可退 要想理解回溯的本质&#xff0c;还是要通过具体的题目去学习。 路径问题 https://www.nowcoder.com/practice/b736e784e3e34731af99065031301b…

【RL】Value Function Approximation(值函数逼近)

Lecture 8: Value Function Approximation Algorithm for state value estimation Objective function 令 v π ( s ) v_{\pi}(s) vπ​(s)和 v ^ ( s , w ) \hat{v}(s, w) v^(s,w)是真实state value和近似函数。 算法的目标是找到一个最优的 w w w&#xff0c;使得 v ^ …

基于微信小程序的比赛赛程管理系统设计与实现

在全面健身的倡导下通过各级赛事的举办完成体育人才的选拔&#xff0c;当由于缺乏信息化的管理手段而只能通过人工完成比赛报名、赛程制定及成绩记录等流程的管理&#xff0c;因此常常因意外而导致比赛赛程管理不善、成绩不理想等问题出现。为了帮助比赛组织者优化赛程管理流程…

0220作业

C语言实现LED1闪烁 led.h #ifndef __LED_H__ #define __LED_H__//RCC寄存器封装 #define RCC_MP_AHB4_ENSETR (*(volatile unsigned int*)0x50000A28) //寄存器封装//GPIO寄存器封装 typedef struct{volatile unsigned int MODER; //00volatile unsigned int OTYPER; //04vol…

环信IM Android端实现华为推送详细步骤

首先我们要参照华为的官网去完成 &#xff0c;以下两个配置都是华为文档为我们提供的 1.https://developer.huawei.com/consumer/cn/doc/HMSCore-Guides/android-config-agc-0000001050170137#section19884105518498 2.https://developer.huawei.com/consumer/cn/doc/HMSCore…

TikTok 被正式诉讼;马斯克称特斯拉一年前就能精确生成真实世界视频丨 RTE 开发者日报 Vol.147

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

释放软件资产的无限潜力:如何通过有效的管理实现价值最大化!

随着数字化时代的加速发展&#xff0c;软件资产已成为企业最重要的资产之一。然而&#xff0c;许多企业并未意识到软件资产管理的重要性&#xff0c;导致软件资产的价值无法得到充分发挥。本文将探讨软件资产管理的重要性&#xff0c;以及如何通过有效的管理实现软件资产价值的…

STL常用之vector,list,stack,queue,deque总结与对比

一&#xff0c;vector 1&#xff09;底层 vector的底层是开辟出来的一块连续空间&#xff0c;类似于数组&#xff0c;每次空间满了之后会根据不同的编译器有不同的扩容倍数。 2&#xff09;优劣 优点&#xff1a;随机访问效率高&#xff0c;因为地址是连续的&#xff0c;底层…

缓存驱动联邦学习架构赋能个性化边缘智能 | TMC 2024

缓存驱动联邦学习架构赋能个性化边缘智能 | TMC 2024 伴随着移动设备的普及与终端数据的爆炸式增长&#xff0c;边缘智能&#xff08;Edge Intelligence, EI&#xff09;逐渐成为研究领域的前沿。在这一浪潮中&#xff0c;联邦学习&#xff08;Federated Learning, FL&#xf…

【2024软件测试面试必会技能】python(3):python自动化测试项目的编写规则类和实例的调用

python -m pip install --upgrade pip 下载最新pip版本 python 项目的命名规则: 项目命名&#xff1a; 大写下划线 包/文件夹 &#xff1a;下划线命名法 html_report 小写下划线 模块名/文件名&#xff1a; 下划线命名法 小写下划线 类&#xff1a;驼峰式命名法 首字母大写 Lo…