前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java的函数式接口以及Lambda表达式

Java的函数式接口以及Lambda表达式

作者头像
半月无霜
发布2023-03-03 14:54:10
4200
发布2023-03-03 14:54:10
举报
文章被收录于专栏:半月无霜

Java的函数式接口以及Lambda表达式

一、介绍

java中,大家肯定使用过lambda表达式吧,这是适用于函数式接口的一种便捷写法。

那么什么是函数式接口,简单点来说,一个接口中有且只有一个需要实现的方法,那么这个接口就是函数式接口

如果一个接口,你想定义为函数式接口,建议加上注解@Functionionallnterface,标注这个接口成为函数式接口,用来进行提示。

例如,多线程的Runnable接口就是一个函数式接口,如下

代码语言:javascript
复制
package java.lang;

@FunctionalInterface
public interface Runnable {
    
    public abstract void run();
}

所以,我们在使用多线程时,可以使用lambda表达式进行简化

代码语言:javascript
复制
package com.banmoon.test;

import org.junit.jupiter.api.Test;

public class SomethingTest {

    @Test
    public void test() {
        // 匿名内部类写法
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类写法");
            }
        }).start();

        // lambda表达式,小括号是入参,大括号是函数式接口中唯一方法的实现
        new Thread(() -> {
            System.out.println("lambda表达式写法");
        }).start();

        // 方法实现只有单行时,可以再简写,省略大括号
        new Thread(() -> System.out.println("lambda表达式写法")).start();
    }

}

二、常用的函数式接口

1)Function<T, R>

先看源码,发现里面居然有四个方法。又仔细一看,确实里面仅有一个apply方法需要实现,所以Function也是一个函数式接口。

代码语言:javascript
复制
package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

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

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

这个函数式接口,接受有两个泛型,一个作为入参,一个作为出参

我第一时间就想到了转换类型,来看这个,从Integer转换为String,且内部做了一定的处理

代码语言:javascript
复制
package com.banmoon.test;

import org.junit.jupiter.api.Test;

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

public class SomethingTest {

    @Test
    public void test() {
        List<Integer> list = new ArrayList<Integer>(){{
            add(7); add(5); add(1); add(2);
            add(8); add(4); add(3); add(6);
            add(3); add(6); add(3); add(6);
        }};

        Function<Integer, String> myFunction = new Function<Integer, String>() {
            @Override
            public String apply(Integer i) {
                return "你好" + i;
            }
        };
        List<String> stringList = list.stream().map(myFunction).collect(Collectors.toList());
        System.out.println(stringList);

		// 使用lambda表达式
        List<String> stringList1 = list.stream().map((i) -> {
            return "你好" + i;
        }).collect(Collectors.toList());

        // 再简写,当参数仅有一个时,小括号可以省略
        stringList1 = list.stream().map(i -> {
            return "你好" + i;
        }).collect(Collectors.toList());
        
        // 再简写,当实现的方法仅有一行语句时,大括号及return可以省略
        stringList1 = list.stream().map(i -> "你好" + i).collect(Collectors.toList());
        System.out.println(stringList1);
    }

}
image-20220526160554725
image-20220526160554725

看下stream接口中的这个map方法,需要我们传入一个Function接口的实现类对象,使用lambda表达式轻松实现对函数式接口的实现类对象的构建

代码语言:javascript
复制
package java.util.stream;

public interface Stream<T> extends BaseStream<T, Stream<T>> {
    
    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
}

2)Predicate<T>

先看源码,泛型只需要指定一个,需要实现的方法一个入参,出参是boolean,作用于判断的一个函数式接口。

代码语言:javascript
复制
package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface Predicate<T> {

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

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

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

来查看使用

代码语言:javascript
复制
package com.banmoon.test;

import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class SomethingTest {

    @Test
    public void test() {
        List<Integer> list = new ArrayList<Integer>(){{
            add(7); add(5); add(1); add(2);
            add(8); add(4); add(3); add(6);
            add(3); add(6); add(3); add(6);
        }};

        Predicate<Integer> myPredicate = new Predicate<Integer>() {
            @Override
            public boolean test(Integer i) {
                return i>5;
            }
        };

        List<Integer> filterList = list.stream().filter(myPredicate).collect(Collectors.toList());
        System.out.println(filterList);

        // lambda表达式简化
        filterList = list.stream().filter(i -> i > 5).collect(Collectors.toList());
        System.out.println(filterList);
    }

}
image-20220526164200162
image-20220526164200162

看下stream接口中的这个filter方法,需要我们传入一个Predicate接口的实现类对象

代码语言:javascript
复制
package java.util.stream;

public interface Stream<T> extends BaseStream<T, Stream<T>> {
    
	Stream<T> filter(Predicate<? super T> predicate);
}

3)Consumer<T>

看类名也能看出来,这是一个消费型的函数式接口,有入参,但没有返回值

代码语言:javascript
复制
package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

使用如下

代码语言:javascript
复制
package com.banmoon.test;

import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;

public class SomethingTest {

    @Test
    public void test() {
        List<Integer> list = new ArrayList<Integer>(){{
            add(7); add(5); add(1); add(2);
            add(8); add(4); add(3); add(6);
            add(3); add(6); add(3); add(6);
        }};

        Consumer myConsumer = new Consumer() {
            @Override
            public void accept(Object o) {
                if(Objects.equals(o, 6))
                    return;
                System.out.print(o);
            }
        };
        list.forEach(myConsumer);

        // lambda表达式简化
        System.out.println("\n========== 分割线 ==========");
        list.forEach(a -> {
            if(Objects.equals(a, 6))
                return;
            System.out.print(a);
        });
    }

}
image-20220526170453349
image-20220526170453349

查看forEach方法的源码,需要我们传入一个Consumer接口的实现类对象

代码语言:javascript
复制
package java.lang;

import java.util.Iterator;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;

public interface Iterable<T> {

    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

}

总有人问,为什么forEach方法不能使用breakcontinue。现在看了源码,你还有这样的疑问吗?

4)Supplier<T>

供给型接口,只有出参,没有入参。在使用上并不多见,先看源码

代码语言:javascript
复制
package java.util.function;

@FunctionalInterface
public interface Supplier<T> {

    T get();
}

查看使用

代码语言:javascript
复制
package com.banmoon.test;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;

public class SomethingTest {

    @Test
    public void test() {
        List<User> list = new ArrayList<User>() {{
            add(new User("半月1", 18, 90));
            add(null);
        }};

        Supplier<User> mySupplier = new Supplier() {
            @Override
            public Object get() {
                return new User("未知", 0, 0);
            }
        };
        list.forEach(a -> {
            User user = Optional.ofNullable(a)
                    .orElseGet(mySupplier);
            System.out.println(user);
        });

        System.out.println("========== 分割线 ==========");
        // lambda表达式简化
        list.forEach(a -> {
            User user = Optional.ofNullable(a)
                    .orElseGet(() -> new User("未知", 0, 0));
            System.out.println(user);
        });
    }

}

@Data
@AllArgsConstructor
class User {
    private String name;
    private Integer age;
    private Integer score;
}
image-20220526175924101
image-20220526175924101

查看Optional的源码,这个方法主要作用是,当前对象为null值后,将使用供给的对象

代码语言:javascript
复制
package java.util;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public final class Optional<T> {

    private final T value;

    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

}

三、最后

上面例举的四个函数式接口,是比较经典的,在很多简化的代码中都可以看到他们的身影。

java8之后,lambda表达式出现,极大地提高了开发的效率,也使得java复杂臃肿的代码得到了缓解。

可谁知道,java8的发布时间在2013年9月份呢,距今都已经有9年的时间了,如果还不了解这上面这些接口,建议先使用Stream流处理。一段时间后,你会明白这些接口的。

使用stream的文章我也有写,可以参考进行学习。

我是半月,祝你幸福!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java的函数式接口以及Lambda表达式
    • 一、介绍
      • 二、常用的函数式接口
        • 1)Function<T, R>
        • 2)Predicate<T>
        • 3)Consumer<T>
        • 4)Supplier<T>
      • 三、最后
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档