匿名内置类
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);
}