强化基础-Java-函数式设计

匿名内置类

Java作为一面向对象的静态语言,其封装性能够屏蔽数据结构的细节,从而更加关注模块的功能性。其静态性也确保了Java强类型的特性。随着模块功能的提升,伴随而来的是复杂度的增加,代码的语义清晰依赖于开发人员抽象和命名类或方法的能力。尽管编程思想和设计模式能够促使编程风格趋于统一,然而大多数业务系统属于面向过程的方式,这与面向对象编程在一定程度 上存在一些冲突。Java 编程语言为了解决这个问题,引入了匿名内置类的方案。

匿名内置类特性

1 无名称类。
2 申明位置:static模块,示例Block 构造器里面也可以写。

public class T {
    static {
        new BaseMethod() {
            @Override
            public void echo() {
                
            }
        };
    }
    {
        new BaseMethod() {
            @Override
            public void echo() {

            }
        };
    }
    public T() {
        new BaseMethod() {
            @Override
            public void echo() {

            }
        };
    }
}

3 内置类其实在底层也是有类文件的,只不过是JVM帮我们生成的。
4 匿名内置类的实现也可以是实现抽象类。允许多个抽象方法。如果在接口里面方法是默认实现了,则匿名内置类可以不实现这个方法。

// 可以实现抽象类
new AbstarctMethod() {
    @Override
    void echo() {
        
    }

    @Override
    void demo() {

    }
}
public interface BaseMethod {
    void echo();
    default void demo() {

    }
}
// 可以不实现 demo方法因为已经有默认实现了
new BaseMethod() {
    @Override
    public void echo() {

    }
}
匿名内置类的局限性

1 代码臃肿
2 强制类型约束,也就是说我们必须指定具体的类型
3 接口方法升级的时候不太好弄,比如我们有三个方法,那如果要升级为4个方法,改动比较大。

Lambda表达式

基本特点

流程编排清晰
函数式编程
改善代码臃肿
兼容接口升级 因为接口有默认实现

局限性

单一的抽象方法 (也就是说只能实现一个抽象方法)
调试困难
Stream API 能力有限

常见的函数式接口

Supplier + Consumer + Function + Predicate + Action
函数式接口是引用一段执行代码
函数式接口没有固定的类型(就是说不需要确定它是什么类型),只有固定的模式(SCFP+ action)
利用方法引用来实现模式的匹配(也就是关联一段可执行的代码)
也就是函数式设计都是引用一段代码,这个代码基本是引用一个模板

1 提供者(没有输入,提供一个内容)

Supplier<String> supplier = new Supplier<String>() {
    @Override
    public String get() {
        return "hello";
    }
};
String s = supplier.get();

2 消费者有输入没有输出,重点是在消费这个内容

// 消费数据
Consumer<String> consumer = new Consumer<String>() {
    @Override
    public void accept(String o) {
        System.out.println(o);
    }
};
consumer.accept("hello");

3 Function模式 有输入输出

Function<String, Integer> function = new Function<String, Integer>() {
     @Override
     public Integer apply(String s) {
         return Integer.parseInt(s);
     }
 };
 Integer apply = function.apply("30");
 System.out.println(apply);

4 Predicate

Predicate<String> h = new Predicate<String>() {
    @Override
    public boolean test(String o) {
        return o.contains("h");
    }
};
boolean res = h.test("hello");
System.out.println(res);

5 Action 执行一个行为

new Runnable() {
    @Override
    public void run() {
        System.out.println("hhh");
    }
}

@FunctionalInterface

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

@FunctionalInterface
public static interface FunctionOne {
    void echo();
}
FunctionOne one = () -> {
    System.out.println("function");
};

函数式接口有5种类型,上文也有介绍,不过上面倾心于演示Lambda表达式。

Supplier
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

示例:

Supplier<String> supplier = () -> {
    return "hello";
};
supplier.get()
Consumer
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
    // andThen 返回的也是一个函数式接口
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}
Consumer<String> one = new Consumer<String>() {
     @Override
     public void accept(String s) {
         System.out.println(s);
     }
 };
 Consumer<String> two = new Consumer<String>() {
     @Override
     public void accept(String s) {
         System.out.println(s + "two");
     }
 };
 // 链式调用
 one.andThen(two).accept("hello");
Function

也支持链式调用有输入和输出

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

示例:

Function<String, Long> s2l = Long::valueOf;
// 执行 先执行 Long -> String  然后再执行 String -> Long 也就是先执行compose
// 注意对比
// andThen 是链式调用 也就是先先执行 String -> Long 再执行 Long -> String
 String apply = s2l.andThen(String::valueOf).apply("1");
Predicate

提供了And 和 Or

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

底层实现:

// 匿名内置类
new Runnable() {
   @Override
   public void run() {
       
   }
};
// invokeDynamic 也就是lambda 是通过指令来实现的 @Since 1.7 MethodHandle 类
Runnable runnable = () -> {
   
};

灵活的使用函数设计

Supplier

可以做方法构造参数,方法返回值
1 延迟加载 用作方法参数

public static void main(String[] args) {
     echo("hello");
     // 延迟加载
     echo(() -> {
         try {
             Thread.sleep(1000);
         } catch (InterruptedException e) {
             throw new RuntimeException(e);
         }
         return "hello";
     });
 }
 public static void echo(String msg) {
     System.out.println(msg);
 }
 public static void echo(Supplier<String> msg) {
 	 // 在get的时候才会触发代码的执行,在这里之前其实还是一段代码的引用
     System.out.println(msg.get());
 }
Consumer

可以做方法构造参数,常常用于callBack

public static void main(String[] args) {
     Consumer<String> consumer = (result) -> {
         System.out.println("执行完成");
         System.out.println(result);
     };
     // 当字符串拼接完成以后 进行回调
     echo(consumer);
 }
 public static void echo(Consumer<String> consumer) {
     StringBuilder builder = new StringBuilder();
     for (int i = 0; i < 10; i ++) {
         builder.append(i);
     };
     consumer.accept(builder.toString());
 }
Function

所为方法/构造参数
用于类型转换,业务处理等

// 比如Stream种的map方法
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
Predicate
Stream<T> filter(Predicate<? super T> predicate);
public static <E> Collection<E> filter(Collection<E> source, Predicate<E> predicate) {
      // 集合类型的操作不要直接使用参数 这是保证源不被操作 与线程安全问题密切相关 
      List<E> copy = new ArrayList<>();
      Iterator<E> iterator = copy.iterator();
      while (iterator.hasNext()) {
          E ele = iterator.next();
          if (!predicate.test(ele)) {
              iterator.remove();
          }
      }
      return Collections.unmodifiableCollection(source);
  }
  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值