java8函数式编程

原创
2016/06/03 08:19
阅读数 77

   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

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部