1. 四大核心函数式接口
1.1 Consumer
消费型接口,有T类型的入参,无反参
void accept(T t);
1.2 Supplier
供给型接口,无入参,有T类型的反参
T get();
1.3 Function
函数式接口,有T类型的入参,有R类型的反参
R apply(T t);
1.4 Predicate
断言型接口,有T类型的入参,有boolean类型的反参
boolean test(T t);
2. 其他函数接口
2.1 BiConsumer
两个入参的消费型接口,T,U
void accept(T t, U u);
2.2 BiFunction
两个入参的函数式接口,入参T,U,反参R
R apply(T t, U u);
2.3 UnaryOperator
对参数类型T进行操作,入参T,反参T,为Function的子接口
public interface UnaryOperator<T> extends Function<T, T> { static <T> UnaryOperator<T> identity() { return t -> t; } }
3. 实际应用
3.1 痛点
使用EasyExcel进行excel进行导入
EasyExcel的 读操作 需要实现 ReadListener
接口以及定义一个映射 T
泛型存储数据行的实体。
如:示例中的 DemoDataListener
和 DemoData
public class DemoDataListener implements ReadListener<DemoData> { // 省略具体的方法实现 }
由于每次导入都要写一个Listener,非常麻烦,就想有没有一个能减少劳动力的方法呢?
3.2 实现解决
就利用了消费型接口
Consumer<T>
去做了实现
3.2.1 实现ReadListener,这里实现的是抽象类AnalysisEventListener,也是一个ReadListener
public class EasyExcelConsumerListener<T> extends AnalysisEventListener<T> { private final List<T> list; private final Consumer<List<T>> consumer; public EasyExcelConsumerListener(Consumer<List<T>> consumer){ this.consumer = consumer; list = new ArrayList<>(); } public void invoke(T data, AnalysisContext context) { list.add(data); } public void doAfterAllAnalysed(AnalysisContext context) { consumer.accept(list); } }
3.2.2 扩展EasyExcel
public class EasyExcelUtil extends EasyExcel { private EasyExcelUtil() { } public static <T> ExcelReaderBuilder read(InputStream inputStream, Class<T> head, Consumer<List<T>> consumer) { return read(inputStream, head, new EasyExcelConsumerListener<>(consumer)); } }
3.2.3 使用
在 Controller
层的代码实现,其中 ExcelData.class
是需要映射的数据实体类,这个映射实体类好像不能投机取巧了~~~
"/excel") (public class ExcelController { private IExcelService service; "/importExcel") ( public R importExcel(MultipartFile file) throws IOException { // service层执行具体的importExcel方法实现 EasyExcelUtil.read(file.getInputStream(), ExcelData.class, service::importExcel).sheet().doRead(); return R.success("导入成功!"); } }
这样就可以关注具体的业务实现啦
3.2.4 使用两个参数的 BiConsumer<T, U>
,与上面的 Consumer<T>
异曲同工
实现 Listener
/** * 异步导入 * 由于获取不到当前登录用户,通过参数传进来 */ public class AsyncBiConsumerListener<T> extends AnalysisEventListener<T> { private final Long userId; private final List<T> list; private final BiConsumer<List<T>, Long> biConsumer; public AsyncBiConsumerListener(BiConsumer<List<T>, Long> biConsumer, Long userId){ this.userId = userId; this.biConsumer = biConsumer; list = new ArrayList<>(); } public void invoke(T data, AnalysisContext context) { list.add(data); } public void doAfterAllAnalysed(AnalysisContext context) { biConsumer.accept(list, userId); } }
扩展 EasyExcel
public class EasyExcelUtil extends EasyExcel { private EasyExcelUtil() { } public static <T> ExcelReaderBuilder read(InputStream inputStream, Class<T> head, Consumer<List<T>> consumer) { return read(inputStream, head, new EasyExcelConsumerListener<>(consumer)); } public static <T> ExcelReaderBuilder read(InputStream inputStream, Class<T> head, BiConsumer<List<T>, Long> biConsumer, Long userId) { return read(inputStream, head, new AsyncBiConsumerListener<>(biConsumer, userId)); } }
使用
public void importExcel(InputStream file, String key, Long userId) { try { EasyExcelUtil.read(file, ExcelData.class, service::importExcel, userId).sheet().doRead(); } catch (Exception ex) { log.error("异步导入异常:", ex); } }