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<T>

读音 /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.5 中台2.0设计

  • com.megvii.galaxy.alarm.warning.service.result.ResultService

   public Stream<RealtimeVideoWarning> realtimeWarningOf(Supplier<RealtimeVideoWarning> supplier,

       Map<String, List<String>> typeTaskIdMap, Map<String, String> strategyTypeMap) {

     return typeTaskIdMap

         .entrySet()

         .stream()

         .map(entry -> {

           // 实际执行

           RealtimeVideoWarning warning = supplier.get();

           warning.setStrategyTypeId(entry.getKey());

           warning.setStrategyTypeName(strategyTypeMap.get(entry.getKey()));

           warning.setAlarmStrategyIds(entry.getValue());

           return warning;

         });

   }

调用代码

  • capture::toWarning 为 Supplier 模式+返回值 RealtimeVideoWarning

   public Stream<RealtimeVideoWarning> build(ResultService service) {

 //    toWarning构造告警数据,warningOf为每条告警记录设置strategyType和alarmStrategyIds

     Stream<RealtimeVideoWarning> warnings = service

         .realtimeWarningOf(capture::toWarning, typeTaskIdMap, strategyTypeMap);

 //    实时车牌识别

     if (compare != null) {

       Stream<RealtimeVideoWarning> warningsLicense = service

           .warningOf(capture::toWarning, compare, strategyTypeMap);

 

       warnings = Stream.concat(warnings, warningsLicense);

     }

原始写法

   private RealtimeVideoCapture capture;

 

   public Stream<RealtimeVideoWarning> realtimeWarningOf(

       Map<String, List<String>> typeTaskIdMap, Map<String, String> strategyTypeMap) {

     return typeTaskIdMap

         .entrySet()

         .stream()

         .map(entry -> {

           RealtimeVideoWarning warning = capture.toWarning();

           warning.setStrategyTypeId(entry.getKey());

           warning.setStrategyTypeName(strategyTypeMap.get(entry.getKey()));

           warning.setAlarmStrategyIds(entry.getValue());

           return warning;

         });

   }

看起来好像原始写法更简单些,也容易理解,那么 Supplier 优势在哪里?

Supplier 这种设计的优势在于 Supplier 作为一个参数传递进来,Supplier 的具体方法的实现可以非常灵活,只要是这种 Supplier 模式,并且返回值是 RealtimeVideoWarning 就可以;而原始写法这个地方是写死的,即使是用设计模式,这个地方可能也要加入一定量的代码,但是用函数式设计可以很优雅。

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<T>

4.2.1 Consumer<T> 接口定义

  • 基本特点:只进不出

  • 编程范式:作为方法/构造参数

  • 使用场景:执行 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<T,R>

4.3.1 Function<T,R> 接口定义

  • 基本特点:有进有出

  • 编程范式:作为方法/构造参数

  • 使用场景:类型转换、业务处理等

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.4 中台2.0分页

  • com.megvii.galaxy.alarm.sdk.model.common.vo.Page

 public class Page<T> {

 

   private final long pageNo;

   private final long pageSize;

   private final long totalPage;

   private final long totalRecords;

   private final long showPage;

   private final long showRecords;

   private final List<T> records;

 

   public <U> Page<U> map(Function<T, U> function) {

     return new Page<>(

         this.pageNo,

         this.pageSize,

         this.totalPage,

         this.totalRecords,

         this.showPage,

         this.showRecords,

         this.records

             .stream()

             .map(function)

             .collect(toList())

     );

   }

 }

将 Stream 的 map 方法嫁接到 Page 中使用。

public Page<CameraPageVo> queryCameraAll(CameraQueryAllRequest request) {

    PageUtil.PageBuilder pageBuilder = PageUtil.of(request.getPageNo(), request.getPageSize());

    ISelect select = adminSearch(request);

    Page<WeekendSqlDemo.Camera> page = pageBuilder.doSelect(select, "create_time desc");

    return page.map(camera -> {

        CameraPageVo vo = new CameraPageVo();

        BeanUtils.copyProperties(camera, vo);

        return vo;

    });

}

将 Dto 转成 Vo。

4.3.5 Spring

  • org.springframework.core.convert.converter.Converter

 public interface Converter<S, T> {

 

     T convert(S source);

 

 }

4.4 Predicate<T>

4.4.1 Predicate<T>接口定义

  • 基本特点:有进有出

  • 编程范式:作为方法/构造参数

  • 使用场景:类型转换、业务处理等

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(12345);

         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(12345).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 表达式的参数和返回类型

  • 将函数式接口作为方法的参数来进行使用,增加程序设计的灵活性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值