Simplememory

V1

2023/03/19阅读:15主题:橙心

lambda表达式总结,建议收藏

lambda表达式总结

什么是lambda

Lambda表达式是JDK8开始后的一种新语法形式,是一个匿名函数方法,可以取代大部分的匿名内部类,写出更优雅的Java代码,特别在集合的遍历以及其他的操作中,可以极大的优化代码结构,其本质属于函数式编程的概念。

函数式接口

  • 函数接口即只有一个抽象方法的接口,用作 Lambda 表达式的类型。
  • @FunctionalInterface注解修饰的类,编译器会检测该类是否只有一个抽象方法或接口,否则,会报错。可以有多个默认方法,静态方法。

Java8常用的函数式接口

函数接口 抽象方法 主要功能 参数 返回值类型
Supplier T get() 生产消息 T
Consumer accept(T t) 消费消息 T void
Predicate test(T t) 判断真假 T boolean
Function R apply(T t) 将T映射为R(实现转换的功能) T R

Supplier接口

Supplier是一个供给型接口,其中的get方法用于返回一个值;Supplier也有许多的变种,例如IntSupplierLongSupplierBooleanSupplier等。

@FunctionalInterface
public interface Supplier<T{

    /**
     * Gets a result.
     *
     * @return a result
     */

    get();
}
  • java.util.function.Supplier<T>接口仅包含一个无参的方法:T get()。用来获取一个泛型参数指定类型的对象数据。
  • Supplier<T>接口被称之为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据。

使用举例:将一个对象转换为字符串

 /**
  * 转化为string
  *
  * @param object
  * @return
  */

 private static String toStr(Object object) {
  Supplier<String> supplier = () -> object.toString();
  return supplier.get();
 }

Consumer接口

Consumer是一个消费型的接口,接收一个输入参数并且无返回的操作,即拿到某个数据时,进行消费,对该数据进行后续的一些操作。

@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); };
    }
}
  • java.util.function.Consumer<T>接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定。 Consumer接口中包含抽象方法void accept(T t),意为消费一个指定泛型的数据。
  • Consumer接口是一个消费型接口,泛型执行什么类型,就可以使用accept方法消费什么类型的数据,至于具体怎么消费(使用),需要自定义实现等。

使用举例:将一个字符串进行反转输出

public static void reverseStr(String sourceStr, Consumer<String> consumer) {
 consumer.accept(sourceStr);
}

reverseStr("acdmshrfalo", (String str) -> {
   String reverseStr = new StringBuffer(str).reverse().toString();
   System.out.println("源字符串:" + str + ",反转后的字符串: " + reverseStr);

 });

Predicate接口

Predicate接口对某种数据类型的数据进行判断,返回一个布尔值。

@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);
    }

    /**
     * Returns a predicate that represents the logical negation of this
     * predicate.
     *
     * @return a predicate that represents the logical negation of this
     * predicate
     */

    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * OR of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code true}, 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-ORed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * OR of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */

    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    /**
     * Returns a predicate that tests if two arguments are equal according
     * to {@link Objects#equals(Object, Object)}.
     *
     * @param <T> the type of arguments to the predicate
     * @param targetRef the object reference with which to compare for equality,
     *               which may be {@code null}
     * @return a predicate that tests if two arguments are equal according
     * to {@link Objects#equals(Object, Object)}
     */

    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}
  • java.util.function.Predicate 接口 作用:对某种数据类型的数据进行判断,结果返回一个boolean值。
  • Predicate接口中包含一个抽象方法:boolean test(T t):用来对指定数据类型数据进行判断的方法;结果符合条件返回true,否则返回false。

使用示例:判断字符串的长度是否大于6,并把判断的结果返回

public static boolean judgeStrLength(String str, Predicate<String> predicate){
 return predicate.test(str);
}

boolean result = judgeStrLength("SimpleMemory公众号", (str) ->
    str.length() > 8
  );
System.out.println("字符串长度是否大于8 = " + result);

Function接口

Function是一个功能型的接口,用于将一种类型的数据转化为另外一种类型的数据。

@FunctionalInterface
public interface Function<TR{

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */

    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));
    }

    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {@code after} 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 output of the {@code after} function, and of the
     *           composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     * @throws NullPointerException if after is null
     *
     * @see #compose(Function)
     */

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /**
     * Returns a function that always returns its input argument.
     *
     * @param <T> the type of the input and output objects to the function
     * @return a function that always returns its input argument
     */

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
  • java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。
  • Function接口中最主要的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果。

使用示例:将一个字符串类型的整数转化为Integer类型

public static Integer toInteger(String str, Function<String, Integer> function) {
  return function.apply(str);
}

Integer integer = toInteger("389", str -> Integer.parseInt(str));
System.out.println("integer = " + integer);

自定义函数式接口

通过自定义函数式接口实现数值运算

@FunctionalInterface
public interface CalFunctionalInterface<TR{
 cal(T t1, T t2);
}
CalFunctionalInterface<Integer, Integer> add =  (t1, t2) -> t1 * t2;
Integer addValue = add.cal(12,23);

以上介绍了lambda接口的简单使用,以及几种常用的函数式接口;接下来将会介绍在Java8中函数式接口在流中是怎样帮助我们高效地处理集合的。

Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。

Stream的使用

创建Stream

创建Stream主要有以下几种方法;

  • 通过 java.util.Collection.stream() 方法用集合创建流
ArrayList<String> arrayList = CollUtil.toList("aaa""bbb""ccc");
Stream<String> stream = arrayList.stream(); // 创建一个顺序流
Stream<String> stringStream = arrayList.parallelStream(); // 创建一个并行流
  • 使用java.util.Arrays.stream(T[] array)方法用数组创建流
int[] array = {1,2,3,7,9,13};
IntStream stream = Arrays.stream(array);
  • 使用Stream的静态方法创建:of()、iterate()、generate()
Stream<Integer> stream = Stream.of(123456);

Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
stream2.forEach(System.out::println);

Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
stream3.forEach(System.out::println);

collect(Collectors.toList())

collect(Collectors.toList())是将流转换为List

List<Student> studentList = Stream.of(
    new Student("000001""张三"12"江苏省苏州市"),
    new Student("000002""李四"13"江苏省南京市"),
    new Student("000003""李红"12"安徽省合肥市"))
    .collect(Collectors.toList());
System.out.println("studentList = " + studentList);

结果:

studentList = [Student(id=000001, name=张三, age=12, address=江苏省苏州市), Student(id=000002, name=李四, age=13, address=江苏省南京市), Student(id=000003, name=李红, age=12, address=安徽省合肥市)]

除此之外,还有.collect(Collectors.toSet()).collect(Collectors.toMap(Student::getId, Function.identity()))等。

Set<Student> studentSet = Stream.of(
      new Student("000001""张三"12"江苏省苏州市"),
      new Student("000002""李四"13"江苏省南京市"),
      new Student("000003""李红"12"安徽省合肥市"))
    .collect(Collectors.toSet());
System.out.println("studentSet = " + studentSet);

结果:

studentSet = [Student(id=000001, name=张三, age=12, address=江苏省苏州市), Student(id=000002, name=李四, age=13, address=江苏省南京市), Student(id=000003, name=李红, age=12, address=安徽省合肥市)]

Map<String, Student> studentMap = Stream.of(
      new Student("000001""张三"12"江苏省苏州市"),
      new Student("000002""李四"13"江苏省南京市"),
      new Student("000003""李红"12"安徽省合肥市"))
    .collect(Collectors.toMap(Student::getId, Function.identity()));
System.out.println("studentMap = " + studentMap);

结果:

studentMap = {000003=Student(id=000003, name=李红, age=12, address=安徽省合肥市), 000002=Student(id=000002, name=李四, age=13, address=江苏省南京市), 000001=Student(id=000001, name=张三, age=12, address=江苏省苏州市)}

以下使用的测试代码:

Student类

@Data
@ToString
@AllArgsConstructor
public class Student implements Serializable {
   private String id;
   private String name;
   private int age;
   private String address;
}
List<Student> studentArrayList = new ArrayList<>();
studentArrayList.add(new Student("000001""张三"12"江苏省苏州市"));
studentArrayList.add(new Student("000002""李四"13"江苏省南京市"));
studentArrayList.add(new Student("000003""李红"12"安徽省合肥市"));

筛选filter

示例:筛选学生年龄小于13岁的学生数据

List<Student> studentList = studentArrayList.stream().filter(item -> item.getAge() < 13).collect(Collectors.toList());
System.out.println("studentList = " + studentList);

输出:

studentList = [Student(id=000001, name=张三, age=12, address=江苏省苏州市), Student(id=000003, name=李红, age=12, address=安徽省合肥市)]

转换map

示例:输出所有学生的姓名信息

List<String> nameList = studentArrayList.stream().map(item->item.getName()).collect(Collectors.toList());
System.out.println("nameList = " + nameList);

输出:

nameList = [张三, 李四, 李红]

最大值max、最小值min

示例:输出所有学生信息中年龄最大以及年龄最小的学生信息

Optional<Student> ageMax = studentArrayList.stream().max(Comparator.comparing(item -> item.getAge()));
// 使用isPresent方法判断是否有值,否则遇到null是直接get()操作引发异常
if (ageMax.isPresent()) {
 Student student = ageMax.get();
 System.out.println("student = " + student);
}
Optional<Student> ageMin = studentArrayList.stream().min(Comparator.comparing(item -> item.getAge()));
// 使用isPresent方法判断是否有值,否则遇到null是直接get()操作引发异常
if (ageMax.isPresent()) {
 Student student = ageMin.get();
 System.out.println("student = " + student);
}

输出:

student = Student(id=000002, name=李四, age=13, address=江苏省南京市) student = Student(id=000001, name=张三, age=12, address=江苏省苏州市)

统计count

示例:统计所有学生中年龄小于13岁的人数

long count = studentArrayList.stream().filter(item -> item.getAge() < 13).count();
System.out.println("count = " + count);

输出:

count = 2

接合joining

joining可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。

示例:将所有学生的姓名输出,并用,作分隔符

String collect = studentArrayList.stream().map(item -> item.getName()).collect(Collectors.joining(","));
System.out.println("collect = " + collect);

输出:

collect = 张三,李四,李红

分组groupingBy

示例:将所有学生信息按性别分组

Map<Integer, List<Student>> collect = studentArrayList.stream().collect(Collectors.groupingBy(Student::getAge));
System.out.println("collect = " + collect);

输出:

collect = {12=[Student(id=000001, name=张三, age=12, address=江苏省苏州市), Student(id=000003, name=李红, age=12, address=安徽省合肥市)], 13=[Student(id=000002, name=李四, age=13, address=江苏省南京市)]}

流的合并concat、去重distinct、限制limit、跳过skip

示例:将两个stream进行合并,并作去重处理

Stream<String> stream1 = CollUtil.toList("aa""bb""cc""dd").stream();
Stream<String> stream2 = CollUtil.toList("bb""cc""ee""ff").stream();
List<String> stringList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
System.out.println("stringList = " + stringList);

输出:

stringList = [aa, bb, cc, dd, ee, ff]

示例:从1开始,输出前10个奇数值

List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
System.out.println("collect = " + collect);

输出:

collect = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

示例:从1开始,跳过前2个元素,输出前6个奇数元素

List<Integer> collect = Stream.iterate(1, x -> x + 2).skip(2).limit(6).collect(Collectors.toList());
System.out.println("collect = " + collect);

输出:

collect = [5, 7, 9, 11, 13, 15]

分类:

后端

标签:

Java

作者介绍

Simplememory
V1