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

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

个人博客地址

一、介绍

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

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

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

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

package java.lang;

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

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

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也是一个函数式接口。

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,且内部做了一定的处理

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

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

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,作用于判断的一个函数式接口。

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

来查看使用

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

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

package java.util.stream;

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

3)Consumer<T>

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

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

使用如下

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

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

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>

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

package java.util.function;

@FunctionalInterface
public interface Supplier<T> {

    T get();
}

查看使用

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

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

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的文章我也有写,可以参考进行学习,点击进行跳转

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值