Java 8 函数式设计,更优雅的使用 Lambda

Java 8 函数式设计,更优雅的使用 Lambda

项目环境

1.前言

本文是函数式接口的基础篇,学完本篇将有助于大家

  • 看懂大神的代码
  • 新增程序设计的新技能
  • 更好的使用 Java 8 新特性,lambda 语法

2.什么是函数式接口 @FunctionalInterface

@FunctionalInterface

用于函数式接口类型声明的信息注解类型,这些接口的实例被 Lambda 表达式、方法引用或者构造器引用创建。函数式接口只能有一个抽象方法,并排除接口默认方法以及声明中覆盖 Object 的公开方法的统计。同时,@FunctionalInterface 不能标注在注解、类以及枚举上。如果违背以上规则,那么接口不能视为函数式接口,当标注 @FunctionalInterface 后,会引起编译错误。

不过,如果任意接口满足以上函数式接口的要求,无论接口是否声明中是否标注 @FunctionalInterface ,均能被编译器视作函数式接口。

示例

public class FunctionalInterfaceDemo {
    public static void main(String[] args) {
        Function1 function1 = ()->{

        };

        FunctionalInterfaceWithoutAnnotation function2 = ()->{

        };

    }

    @FunctionalInterface
    public interface Function1 {

        void execute();

        default String getDescription(){
            return String.valueOf(this);
        }

    }

    // @FunctionalInterface 并非必选
    public interface FunctionalInterfaceWithoutAnnotation{
        void execute();
    }
}
  • Function1 中可以看到,如果接口中有多个方法,保留一个接口抽象方法,其他方法必须添加 default 默认实现
  • 如果接口只有一个方法,即使不写 @FunctionalInterface 也会被识别成函数式接口
  • 符合以上条件的接口实例,可以使用 Lambda 表达式来创建

通过上面的例子我们似乎看到了一点点 Lambda 和 @FunctionalInterface 的联系,接下来我们将一步一步来了解 Java 8 中内置的几种函数式接口类型。

3.函数式接口类型

  • 提供类型 - Supplier<T>
  • 消费类型 - Consumer<T>
  • 转换类型 - Function<T,R>
  • 断定类型 - Predicate<T>
  • 隐藏类型 - Action

4.举例说明

泛型类型参数命名约定

  • E:表示集合元素(Element)
  • V:表示数值(Value)
  • K:表示键(Key)
  • T:表示类型(Type)
  • R:表示结果(Result)
  • S:表示来源(Source)

4.1 Supplier

读音 /səˈplaɪər/

4.1.1 Supplier 接口定义
  • 基本特点:只出不进
  • 编程范式:作为方法/构造参数、方法返回值
  • 使用场景:数据来源,代码替代接口
4.1.2 Supplier 接口源码
@FunctionalInterface
public interface Supplier<T> {
    T get();
}
4.1.3 示例
public class SupplierDemo {
    public static void main(String[] args) {
        Supplier<Long> supplier = getLong();
        System.out.println(supplier.get());
    }

     /**
     * 第一种写法
     * @return
     */
    public static Supplier<Long> getLong(){
        return ()->{
            return System.currentTimeMillis();
        };
    }

    /**
     * 第二种写法
     * @return
     */
    public static Supplier<Long> getLongOther(){
        return System::currentTimeMillis;
    }
}
4.1.4 设计

普通版本

public class SupplierDesignDemo {
    public static void main(String[] args) {
        ehco("Hello,World");
    }

    public static void ehco(String message) {
        System.out.println(message);
    }
}

Supplier+Lambda 表达式

  private static void level2() {
    Supplier<String> supplyMessage = () -> {
      return "lambda-Hello,World";
    };
    ehco(supplyMessage.get());
  }

Supplier 作为 ehco 方法参数

  private static void level3() {
    ehco(SupplierDesignDemo::getMessage);
  }

  public static void ehco(Supplier<String> message) {
    System.out.println(message.get());
  }

  public static String getMessage() {
    return "lazy-Hello,World";
  }

执行区别

  • 及时执行
  • 延迟执行
  private static void level4() {
    getMessage();//及时执行
    Supplier<String> message = supplyMessage();//待执行状态
    message.get();//实际执行
  }
4.1.6 Spring 5.0+
public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {

	T getObject(Object... args) throws BeansException;

	@Nullable
	T getIfAvailable() throws BeansException;

	default T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {
		T dependency = getIfAvailable();
		return (dependency != null ? dependency : defaultSupplier.get());
	}
    ...

使用

ObjectProvider<User> beanProvider = applicationContext.getBeanProvider(User.class);
System.out.println(beanProvider.getIfAvailable(User::createUser));

运来这一步可能使用 beanFactory.getBean(User.class) 直接获取 Spring IoC 容器中的 User 对象,如果容器中没有就会报错;但是使用 beanProvider.getIfAvailable(User::createUser),相当于给了一个默认值(方法),如果容器没有的话就使用 User::createUser 来创建 User 对象,并返回。

4.2 Consumer

4.2.1 Consumer 接口定义
  • 基本特点:只进不出
  • 编程范式:作为方法/构造参数
  • 使用场景:执行 Callback
4.2.2 Consumer 接口源码
@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); };
    }
}

普通版本

  public static void level1() {
    System.out.println("xwf");
  }

Consumer 版本

  public static void level2() {
    Consumer<String> consumer = System.out::println;
    consumer.accept("xwf");
  }

自定义方法

  public static void level3() {
    Consumer<String> consumer = ConsumerDemo::echo;
    consumer.accept("xwf");
  }
   
  public static void echo(String str) {
    System.out.println("echo1:" + str);
  }

Consumer#andThen

  public static void displayAndThen() {
    Consumer<String> consumer2 = ConsumerDemo::echo2;

    Consumer<String> consumer3 = ConsumerDemo::echo3;

    Consumer<String> consumer1 = ConsumerDemo::echo;
    // Fluent API
    consumer1.andThen(consumer2).andThen(consumer3).accept("xwf");
  }

  public static void echo(String str) {
    System.out.println("echo1:" + str);
  }

  public static void echo2(String str) {
    System.out.println("echo2:" + str);
  }

  public static void echo3(String str) {
    System.out.println("echo3:" + str);
  }

执行结果

echo1:xwf
echo2:xwf
echo3:xwf
4.2.3 Spring
public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {
    ...
	default void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException {
		T dependency = getIfAvailable();
		if (dependency != null) {
			dependencyConsumer.accept(dependency);
		}
	}
    ...

T 作为参数传递给 Consumer,然后来执行 beanProvider.ifAvailable(System.out::println);

4.3 Function

4.3.1 Function 接口定义
  • 基本特点:有进有出
  • 编程范式:作为方法/构造参数
  • 使用场景:类型转换、业务处理等
4.3.2 源码

将类型 T 转化为类型 R

@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;
    }
}
4.3.3 示例
public class FunctionalDemo {

  public static void main(String[] args) {
    displayCompose();
  }

  /**
   * String -> Integer
   */
  public static void level1() {
    Function<String, Integer> function = Integer::valueOf;
    Integer res = function.apply("1");
    System.out.println(res);
  }

  /**
   * Long -> String
   */
  public static void level2() {
    Function<Long, String> function = String::valueOf;
    String res = function.apply(13L);
    System.out.println(res);
  }

  /**
   * compose
   */
  public static void displayCompose() {
    Function<String, Integer> function = Integer::valueOf;

    // 1 -> "1" -> 1
    Integer value = function.compose(String::valueOf).apply(1);
    System.out.println(value);
  }

}

典型应用

  • java.util.stream.Stream
<R> Stream<R> map(Function<? super T, ? extends R> mapper);

示例

class User {

  private String name;
  private Integer age;

  public User(String name, Integer age) {
    this.name = name;
    this.age = age;
  }

  public User() {
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Integer getAge() {
    return age;
  }

  public void setAge(Integer age) {
    this.age = age;
  }

  public static List<User> getUsers() {
    List<User> users = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
      users.add(new User("person" + i, i));
    }
    return users;
  }
}

将 User 集合转化成 User 的 name 集合,通过 map(User::getName)

    private static void map() {
        List<String> userNames = User.getUsers().stream().map(User::getName)
            .collect(Collectors.toList());
        System.out.println(userNames);
    }

执行结果

[person0, person1, person2, person3, person4, person5, person6, person7, person8, person9]
4.3.5 Spring 类似接口
  • org.springframework.core.convert.converter.Converter
public interface Converter<S, T> {

	T convert(S source);

}

4.4 Predicate

4.4.1 Predicate 接口定义
  • 基本特点:有进有出
  • 编程范式:作为方法/构造参数
  • 使用场景:类型转换、业务处理等
4.4.2 源码
@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);
    }
}
4.4.3 示例
public class PredicateDemo {

    public static void main(String[] args) {

        Predicate<File> predicate = FileFilter::accpet;
        System.out.println(predicate.test(new File("/aaa")));

    }

    static class FileFilter {
        static boolean accpet(File path) {
            return true;
        }
    }

}

典型应用

  • java.util.stream.Stream
Stream<T> filter(Predicate<? super T> predicate);
4.4.4 设计
public class PredicateDesignDemo {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        Collection<Integer> even = filter(numbers, PredicateDesignDemo::condition);
        even.forEach(System.out::println);
    }

    private static boolean condition(Integer number) {
        if (number % 2 == 0) {
            return false;
        } else {
            return true;
        }
    }

    private static <E> Collection<E> filter(Collection<E> source, Predicate<E> predicate) {
        // 集合类操作,请不要直接利用参数
        List<E> copy = new ArrayList<>(source);
        Iterator<E> iterator = copy.iterator();
        while ((iterator).hasNext()) {
            E element = iterator.next();
            if (predicate.test(element)) {
                iterator.remove();
            }
        }
        return Collections.unmodifiableList(copy);
    }
}

以上代码等同于

    List<Integer> collect = Stream.of(1, 2, 3, 4, 5).filter(num -> {
      return num % 2 == 0;
    }).collect(Collectors.toList());

4.5 Action

  • 基本特点:不进不出
  • 使用场景:线程执行
4.5.1 示例
public class ActionDemo {

  public static void main(String[] args) {
    Runnable runnable = new Runnable() {
      @Override
      public void run() {
        System.out.println("Hello,World");
      }
    };

    // invokedynamic 指令 @since jdk 1.7
    // java.lang.invoke.MethodHandle
    // java.lang.invoke.InvokeDynamic
    Runnable runnable2 = () -> {
      System.out.println("Hello,World");
    };
    runnable.run();
  }

}

5.总结

综上所述,函数式接口就是将我们一些特殊的接口方法进行了分类,根据方法参数和返回值来确定属于哪一类型

  • 提供类型 - Supplier<T>
    • 只出不进
  • 消费类型 - Consumer<T>
    • 只进不出
  • 转换类型 - Function<T,R>
    • 有进有出
  • 断定类型 - Predicate<T>
    • 有进有出,返回值为 Boolean 类型
  • 隐藏类型 - Action
    • 不进不出

示例

public class LambdaDemo {

  public static void main(String[] args) {
    // 只出不进
    Supplier<String> supplier = LambdaDemo::getMessage;
    // 只进不出
    Consumer<String> consumer = LambdaDemo::printlnMessage;
    // 有进有出
    Function<Integer,String> function = LambdaDemo::integerToString;
    // 有进有出+判断
    Predicate<Integer> predicate = LambdaDemo::existNumber;
    // Action 隐藏类型 不进不出
    Runnable runnable = ()->{

    };
  }

  public static String getMessage() {
    return "xwf";
  }

  public static void printlnMessage(String msg) {
    System.out.println(msg);
  }

  public static String integerToString(Integer number) {
    return String.valueOf(number);
  }

  public static Boolean existNumber(Integer number) {
    return true;
  }

}

应用场景

  • 函数式接口提供 lambda 表达式和方法引用的目标类型
  • 函数式接口可以匹配或适配为 lambda 表达式的参数和返回类型
  • 将函数式接口作为方法的参数来进行使用,增加程序设计的灵活性
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值