Lambda 优雅的处理编译时异常

一、前言

Lambda 表达式 在日常开发过程中实在是太方便了,功能强大且简化了很多代码。但是遇上编译时异常时候却很尴尬。由于Lambda无法抛出异常,导致你必须要对异常进行捕获。这样写起来的点就很丑。本篇针对这个问题进行了一些改进。

二、示例

  1. 一个简单的集合遍历如下:
	    public static void main(String[] args) {
    
    
	        List<User> list = new ArrayList<>();
	        list.add(new User(1, "张三", "123"));
	        list.add(new User(2, "李四", "321"));
	
	        list.stream().forEach(user -> System.out.println(user.info()));
	    }
	    
		...
		//	user类
		public class User {
    
    
		    private int id;
		    private String name;
		    private String pwd;
		
			...省略get、set和构造函数
		
		    public String info()  {
    
    
		        return "User{" +
		                "id=" + id +
		                ", name='" + name + '\'' +
		                ", pwd='" + pwd + '\'' +
		                '}';
		    }
		}

一句话完成了集合遍历,十分方便。但是如果我们让info抛出一个编译时异常,假设是 IOException。
那么我们就没那么简单遍历了。我们必须要捕获这个IOException 。代码变成了如下形式。

    public static void main(String[] args) {
    
    
        List<User> list = new ArrayList<>();
        list.add(new User(1, "张三", "123"));
        list.add(new User(2, "李四", "321"));

        list.stream().forEach(user -> {
    
    
            try {
    
    
                System.out.println(user.info());
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        });
    }
		...
		//	user类
		public class User {
    
    
		    private int id;
		    private String name;
		    private String pwd;
		
			...省略get、set和构造函数
		
		    public String info() throws IOException{
    
    
		        return "User{" +
		                "id=" + id +
		                ", name='" + name + '\'' +
		                ", pwd='" + pwd + '\'' +
		                '}';
		    }
		}

那么这个流操作就很难受,明明我的业务逻辑很简单,但是却需要写一个try…catch。其实写了也无所谓,关键是代码变丑了!代码变丑了!代码变丑了!

  1. 所以我们想到可以将编译时异常转为运行时异常抛出。

Stream.forEach() 方法如下。可以看到forEach方法并没有抛出异常,从而导致我们在调用forEach时只能在内部捕获异常:

 void forEach(Consumer<? super T> action);

所以我们可以自定义一个MyConsumer接口,抛出异常,如下:

public interface MyConsumer<T> {
    
    
    void apply(T t) throws Throwable;
}

可是光抛出异常没用,我们需要转换异常结构。所以再定义一个接口来进行一个代理(或者说委托,或者说其它,以我的能力,我还没分清 )。我们通过接口回调来处理消息。

public interface Lambda {
    
    
    static <T> Consumer<T> forEach(MyConsumer<T> myConsumer){
    
    
//        return new Consumer<T>() {
    
    
//            @Override
//            public void accept(T t) {
    
    
//                try {
    
    
//                    myConsumer.apply(t);
//                } catch (Throwable throwable) {
    
    
//                    throw new RuntimeException(throwable);
//                }
//            }
//        };
        return t -> {
    
    
            try {
    
    
                myConsumer.apply(t);
            } catch (Throwable throwable) {
    
    
               throw new RuntimeException(throwable);
            }
        };
    };
}

调用就可以变成如下形式,不用再捕获异常了:

    public static void main(String[] args) {
    
    
        List<User> list = new ArrayList<>();
        list.add(new User(1, "张三", "123"));
        list.add(new User(2, "李四", "321"));
        list.stream().forEach(Lambda.forEach(user -> System.out.println(user.info())));
    }

同理再写一个map

public interface MyFunction<T, R> {
    
    
    R apply(T t) throws Throwable;
}

public interface Lambda {
    
    
    static <T> Consumer<T> forEach(MyConsumer<T> myConsumer){
    
    
        return t -> {
    
    
            try {
    
    
                myConsumer.apply(t);
            } catch (Throwable throwable) {
    
    
               throw new RuntimeException(throwable);
            }
        };
    };

    static <T, R> Function<T, R> map(MyFunction<T, R> myFunction){
    
    
        return t -> {
    
    
            try {
    
    
               return myFunction.apply(t);
            } catch (Throwable throwable) {
    
    
                throw new RuntimeException(throwable);
            }
        };
    }
}

调用如下:

扫描二维码关注公众号,回复: 11960637 查看本文章
    public static void main(String[] args) {
    
    
        List<User> list = new ArrayList<>();
        list.add(new User(1, "张三", "123"));
        list.add(new User(2, "李四", "321"));
        // 改造前
        list.stream().forEach(user -> {
    
    
            try {
    
    
                System.out.println(user.info());
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        });
        // 改造后
        list.stream().forEach(Lambda.forEach(user -> System.out.println(user.info())));

        // 改造前
        list.stream().map(user -> {
    
    
            try {
    
    
                return user.info();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
            return null;
        }).collect(Collectors.toList());
        // 改造后
        list.stream().map(Lambda.map(user -> user.info())).collect(Collectors.toList());
    }

三、总结

本篇只作为一个引子,记录一下使用方式。至于后续的通用性扩展,就不再展开。


以上:内容部分参考
https://mp.weixin.qq.com/s/Dvd13G7UE5Zz5gQxlUkiFQ
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正

猜你喜欢

转载自blog.csdn.net/qq_36882793/article/details/103809883