JDK8之后的接口

JDK8绝对可以算是1.6之后的又外一个里程碑式的版本更新,有很多惊艳的更新。今天我们就来聊聊JDK8带来的接口设计上的变动。

概述

JDK8之后,interface接口在语法上做了大改动,注意是3个方面:

1>默认实现

2>静态方法

3>函数接口

默认实现

所谓的默认实现就是接口中不再固定要求只能存在抽象的方法,也快存在非抽象实例方法。

public interface MyInterface { 
    // default修饰符定义默认方法 
    default void defaultMethod() { 
    	System.out.println("接口中的默认方法"); 
    }
}

实现类:

public class MyInterfaceImpl implements MyInterface{
    //可以重写defaultMethod方法,也可以不重写
}

从上面代码上看,实现类即使不重写defaultMethod 方法依然可以正常编译。

此时,肯定会有朋友问,这设计能带来说好处呢?个人看法,主要体现在下面几个方面:

1>减少抽象适配器类

这个不好描述,以例子说明:

例子:Spring拦截器接口:HandlerInterceptor,自定义拦截器需要实现该接口,JDK8之前必须全部重写3个方法,即使大部分业务操作只需要关注preHandler方法的实现。

public class MyHandlerInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        
            return  false;
        }
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

上面实现类其实只需要关注preHandler方法即可,但是接口规则限制,后面的2个方法不得不空实现。为应对这种非必要的接口方法实现,JDK8出来之前应对方案:

抽象适配器类(HandlerInterceptorAdapter):对HandlerInterceptor接口进行空实现,自定义拦截器需要继承该类,并重写需要接口方法。

public class MyHandlerInterceptorAdapter implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        
            return  false;
        }
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
public class MyHandlerInterceptor extends MyHandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            //业务逻辑
        
            return  false;
        }
    }
}

上面解决方案特点:费时又费力,代码结构还复杂,麻烦。

JDK8后引入接口默认实现,自带适配器逻辑,后续自定义拦截器只需要实现HandlerInterceptor接口,然后按需重写接口方法即可

//都是默认实现方法
public interface HandlerInterceptor {
	default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return true;
	}
	default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable ModelAndView modelAndView) throws Exception {
	}

	default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable Exception ex) throws Exception {
	}
}

自定义拦截器

public class MyHandlerInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return false;
    }
}

简单明了

2>兼容以前旧接口的

从接口兼容问题上看,接口默认实现绝对是巧妙至极。

举个例子:

JDK8之前,Collection接口没有以下方法

    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
    default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }

JDK8之后,引入的lambda表达式与Stream操作,一些接口就需要升级啦。如果没有默认实现这骚操作,那之前写过的所有代码就必须改动,重写因为引入lambda表达式与Stream操作而新增的方法。而现在,你会发现,可以无缝兼容,之前代码0改动,同时自动新增了lambda表达式与Stream操作逻辑。

上面例子,所有使用Collection接口的类/子接口,都不需要做任何改动,即可支持Lambda与Stream操作。

静态方法

JDK8之前的接口可以定义变量和方法,变量必须是public、static、final的,方法必须是public、abstract的。JDK8之后可以在接口添加了静态方法。

public interface MyInterface {
    static void dowork(){
        System.out.println("......");
    }
}

测试

public static void main(String[] args) {
    MyInterface.dowork();
}

这时候,我们又得问啦,接口里面添加静态方法,目的是为啥,很简单:快速实现

以Spring-data体系中的Page接口为例子

public interface Page<T> extends Slice<T> {
	static <T> Page<T> empty() {
		return empty(Pageable.unpaged());
	}
	static <T> Page<T> empty(Pageable pageable) {
		return new PageImpl<>(Collections.emptyList(), pageable, 0);
	}
	int getTotalPages();
	long getTotalElements();
	<U> Page<U> map(Function<? super T, ? extends U> converter);
}

Page接口是一个分页信息封装对象,对分页数据与分页条数据进行封装,正常实现应该:PageImpl

public class PageImpl<T> extends Chunk<T> implements Page<T> {
    //....
}

但实际操作中可能存在这种情况:分页总数据为0, 那么就没必要进行分页数据封装了。那么分页逻辑直接返回

Page.empty();  //方便,简单明了,更不需要额外实现类

函数接口

JDK8之后,引入一个新的概念:函数接口

定义:有且仅有一个抽象方法的接口。

public interface MyInterface {
    void dowork();
}

为了明确标记函数接口,使用了标记注解:@FunctionalInterface

@FunctionalInterface
public interface MyInterface {
    void dowork();
}

这里注意,这种写法也算是一个函数接口

@FunctionalInterface
public interface MyInterface {
    void dowork();
    
    default void defaultMethod(){
        System.out.println("default....");
    }
}

默认实现不算是抽象方法。函数接口引入目的是配合Lambda表达跟Stream操作,具体实现后续再展开讲,这里说一个简单例子

线程接口-JDK之后的改造

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

JDK8之前最简单实现 

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

JDK8之后,再进一步简化

new Thread(()-> System.out.println("....")).start();

好了,JDK8之后接口变动就聊到这,下一篇我们来聊聊函数接口。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪飞yes

我对钱没兴趣~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值