Java8引入了很多"让人眼前一亮"的一些新特性,本文先介绍函数式编程(java8 lambda)。
首先想象这么一种应用,在工作生活中总是有可能需要处理一个功能:查询一张表的全部数据,然后将这张表的数据遍历,每条记录写入csv文件。
也许你会采用下面的做法:
//do not do this
public class ExportTabDAO{
@Override
public void persistAll()
throws DataAccessException{
String sql = "select * from ${sometable}";
JdbcTemplate jdbcTemplate = ...;
CsvWriter csvWriter = ...;
jdbcTemplate.query(sql, new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
//下面开始获取表的若干属性
String name = rs.getString(1);
String title = rs.getString(2);
//handle代码和dao层耦合,不是好的设计
csvWriter.writeNext(new String[]{name, title});
}
});
}
}
这种做法有什么不好的呢:在Dao数据处理层,不应该把handle耦合在代码当中(如果下次你还需要把这张表的数据写入到excel,又要在processRow里面写一定处理了,甚至可能需要在重新写一个方法)。
那么正确的做法应该是怎样的呢,我们应该把name,title封装成一个对象,把这个对象交给上层的处理(这里上层的处理不是确定的,有一些上层的处理是要处理成csv,有些上层的处理是要处理成excel)
下面来看一种改善的做法:
public void persistAll(Consumer<Entity> function)
throws DataAccessException{
String sql = "select * from ${sometable}";
JdbcTemplate jdbcTemplate = ...;
//CsvWriter csvWriter = ...; 这里不再需要处理csv了
jdbcTemplate.query(sql, new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
//下面开始获取表的若干属性
String name = rs.getString(1);
String title = rs.getString(2);
//将这几个属性交由上层处理,解决耦合问题
function.apply(new Entity(name,title));
}
});
}
在上层这样子调用:
ExportTabDAO dao = ...;
dao.persistAllBiblios(entity -> {
//do something entity
});
在上面的例子中,我们看到了一种全新的语法和全新的类Consumer(位于java.util.function包中,是一个函数式接口 function interface)
这种全新的语法在java8中称为lambda表达式(可以简单理解为匿名内部类语法糖),也就是没有这种语法糖我们需要下面的写法:
dao.persistAllBiblios(new Consumer<Entity>() {
@Override
public void accept(Entity t) {
//do something t
}
});
当然jdk8中的lambda还可以做很多便捷的操作,例如,你是一名商店的管理者,想知道自己卖的每件商品,在2016年5月的销售记录中,每个商品分类的销售数量的话,有一种做法是使用sql统计出来。但是也可以在程序中计算每个分类的销售数量,如下。
final List<String> types = new ArrayList<String>(10000);
//从销售日志表中获取获取每个商品的分类,加入到list中
Map<String, Integer> map = types.stream().collect(Collectors
.groupingBy(s -> s, Collectors.summingInt(s -> 1)) );
List<Entry<String, Integer>> list = new ArrayList<>(map.entrySet());
//按销量排序取出前几个分类
list.sort(Comparator.comparing((Entry<String, Integer> entry) -> entry.getValue()).reversed());
list.stream().limit(100).forEach(System.out::println);
还有一个例子是我们在开发中有时需要遍历一个项目中的access.log文件(访问日志文件,以此来处理一些操作),用jdk8可以很方便的处理:
Files.list(new File("F:/access/logs").toPath()).forEach(file -> {
Files.lines(file).forEach(line -> {
//dosomething line
});
});
下面是jdk8 Collectors 的在线api,也有介绍jdk8一些函数编程的使用方式:
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html
jdk8中还引入了一些简化并发操作的api,下面是一个小例子:
JdbcTemplate jdbcTemplate = ...;
//统计各个地区的某个日志表日志量总数
List<Pair<String,Integer>> list = Arrays.asList("gz","zj","wh")
.parallelStream().map(area -> {
String tableName = area + "_log";
int cnt = jdbcTemplate.queryForObject(
"select count(1) from " + tableName, Integer.class);
return Pair.of(area, cnt);
}).collect(Collectors.toList());
ps:目前项目用到jdk8的地方还是很多,此文先开个头,并且推荐一本书《java8函数式编程》,下次再补上相关介绍内容(下次更新大概要等到猴年马月吧)
ps:jdk8中java.util.collection集合更新的Stream api太值得学习了
ps:目前个人觉得此篇文章的example太少了
近期学习计划以及文章更新计划如下:
1.继续学习jdk8的一些特性并更新到文章中。
2.个人用一段时间系统学习了一些推荐系统的相关知识,有空补上。
3.maven项目管理相关,学了父子项目,项目聚合,目前未整理相关知识。
4.solr,ElasticSearch这两个搜索引擎框架也要系统学习下了。
5.Spring boot,以及spring-boot-session项目的学习
6.Nginx,redis
7.学习一门可能和技术无关的知识,目前个人正在看一本head first出版的《深入浅出pmp》的书,只看了一点点(该书主要内容范围为项目管理)
8.设计模式、函数式编程持续性学习(目前认为还是要多看源码,然后完善自己的一些代码设计)
9.系统学习一门orm框架例如mybatis
10.安全控制框架也有可能在新项目中应用上,比如可能要学习一下spring-security,以及看下spring-boot如何整合spring-security