语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利

顺带用到一些泛型编程,一切都是为了简化代码

场景:

一个数据类,用于记录职工信息

public class Employee {

    public String name;
public int age;
public char sex;
public String time;
public int salary; }

我们有一列此类数据

List<Employee> data = Arrays.asList(e1,e2,e3......)

现在有需求:将员工Employee按照姓名的首字母(假设均为英文名)进行分组:

那么我们要得到的结果应该是一个Map:char -> List<Employee> 这样的映射关系

public static Map<Character, List<Employee>> groupByFirstChar(
List<Employee> data){
Map<Character, List<Employee>> result = new HashMap<>();
for(Employee e : data){
Character c = e.name.charAt(0);
List<Employee> l = result.get(c);
if(l == null){
l = new ArrayList<>();
result.put(c, l);
}
l.add(e);
}
return result;
}

代码并不复杂,很快就可以完成,老板看你效率这么高,于是说,再按照工资分个组吧,5000以下的,5000~10000的 ...等

也不会太难,将key换一下,稍作逻辑处理即可

public static Map<String, List<Employee>> groupBySalary(List<Employee> data) {
Map<String, List<Employee>> result = new HashMap<>();
for (Employee e : data) {
String key = separate(e.salary);
List<Employee> l = result.get(key);
if (l == null) {
l = new ArrayList<>();
result.put(key, l);
}
l.add(e);
}
return result;
} private static String separate(int salary) {
if (salary <= 5000) {
return "5000以下";
}
if (salary <= 10000) {
return "5000~10000";
}
if (salary <= 20000) {
return "10000~20000";
}
return "20000以上"
}

然后老板又说了,按照员工的入职年份分下组吧。。。

这里就代码就不写了,稍作比较可以发现,无论怎么分组,唯一的变化是key值的选取方式,

第一次将Employee的name的第一字母作为key:

Employee e -> e.name.charAt(0)

第二次将Employee的salary按照方法separat转换为String作为key:

Employee e -> separate(e.salary):String

以此类推

Employee e -> getYear(e.time):String

事实上第一次也可以将获取首字母单独写成一个方法

Employee e -> getFirstChar(e.name):Character

为了看起来更美观,可以讲三个方法的参数都设置成Employee 方法体就不写了 这里只列出参数和返回值

Employee e -> getFirstChar(e) : Character
Employee e -> separate(e) : String
Employee e -> getYear(e) : String

->的左边为参数,:的右边为返回值,->的右边是方法的签名

那么我们自然会想到将变化的部分抽取为参数,其他不变的部分抽取为方法体,那么就可以省去那些重复的代码,显然变化的部分就是上面列出的,将Employee e转化成key的方法,但是我们知道java是不能把方法作为参数进行传递的。不过对于稍有经验的程序猿来说这并不是问题,我们可以使用接口来实现我们的目的,同时又会遇到另一个问题,以上三个方法的返回值是不同的,因此我们要用到泛型:

public static <K> Map<K, List<Employee>> groupByKey(List<Employee> data, GetKey<K> getKey){
Map<K, List<Employee>> result = new HashMap<>();
for(Employee e : data) {
K key = getKey.getKey(e);
List<Employee> l = result.get(key);
if (l == null) {
l = new ArrayList<>();
result.put(key, l);
}
l.add(e);
}
return result;
}
interface GetKey<K>{
K getKey(Employee e);
}

那么上面的第一个需求就可以这样实现

Map<Character, List<Employee>> result = groupByKey(data, new GetKey<Character>() {
@Override
public Character getKey(Employee e) {
e.name.charAt(0);
}
});

第二个需求

Map<String, List<Employee>> result = groupByKey(list, new GetKey<String>() {
@Override
public String getKey(Employee e) {
separate(e.salary);
}
});

可以发现,我们只需要更改泛型参数和匿名内部类的实现即可,唯一的问题恐怕是这么写实在不太好看,而且很多例行公事的代码,尤其体现在匿名内部类上。

事实上我们只关心这个匿名内部类的参数和返回值,其他部分仅仅是语法要求。

java8恰好为我们提供了很好的方式来避免复杂的例行公事的方式:lambda表达式,以上实现就可以写成

Map<Character, List<Employee>> resultByFirstChar = groupByKey(list, e -> e.name.charAt(0));
Map<String, List<Employee>> resultBySalary = groupByKey(list, e -> separate(e.salary));

lambda表达式恰恰只表现出我们所关心的,参数和返回值,同时由于类型推断,可以省去参数类型,具体语法这里就不介绍了,网上可以查到很多资料

extra:

如果你对泛型有不错的了解的话,方法groupByKey还可以进一步抽象:

public static <K, E> Map<K, List<E>> groupBy(List<? extends E> data, Function<? super E, ? extends K> fun) {
Map<K, List<E>> result = new HashMap<>();
for(E e : data) {
K k = fun.apply(e);
List<E> l = result.get(k);
if(l == null) {
l = new ArrayList<>();
result.put(k, l);
}
l.add(e);
}
return result;
}

我们将Employee这个类也抽取了,好处显而易见

Function接口是java8新加入的接口:

@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}

输入一个T类型 返回R类型。泛型和函数式编程结合的很不错,虽然java8的新特性被各种吐槽,但是能带来好处总是好的,这给了我们更多的选择。

有时间的话会介绍stream,java8的另一大利器

java8中lambda表达式的应用,以及一些泛型相关的更多相关文章

  1. Java8中Lambda表达式的10个例子

    Java8中Lambda表达式的10个例子 例1 用Lambda表达式实现Runnable接口 //Before Java 8: new Thread(new Runnable() { @Overri ...

  2. java8中Lambda表达式和Stream API

    一.Lambda表达式 1.语法格式 Lambda是匿名函数,可以传递代码.使用“->”操作符,改操作符将lambda分成两部分: 左侧:指定了 Lambda 表达式需要的所有参数 右侧:指定了 ...

  3. 公子奇带你一步一步了解Java8中Lambda表达式

    在上一篇<公子奇带你一步一步了解Java8中行为参数化>中,我们演示到最后将匿名实现简写为 (Police police) -> "浙江".equals(poli ...

  4. Java8 Collections.sort()及Arrays.sort()中Lambda表达式及增强版Comparator的使用

    摘要:本文主要介绍Java8 中Arrays.sort()及Collections.sort()中Lambda表达式及增强版Comparator的使用. 不废话直接上代码 import com.goo ...

  5. Java8的Lambda表达式简介

    先阐述一下JSR(Java Specification Requests)规范,即Java语言的规范提案.是向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求 ...

  6. java8的lambda表达式,将List<DTO> 转为 List<DO>

    将List<PhoneDTO>转为List<PhoneDO>,通过java8的lambda表达式来操作,比传统的for循环精简很多: /** * List<PhoneDT ...

  7. Java中lambda表达式详解

    原文地址:http://blog.laofu.online/2018/04/20/java-lambda/ 为什么使用lambda 在java中我们很容易将一个变量赋值,比如int a =0;int ...

  8. java8的lambda表达式

    关于java8的lambda表达式 lambda表达式一般用于接口,因为lambda表达式是函数式编程. 1.有且仅有一个抽象方法被称为函数式接口,函数式接口可以显示的被@FunctionalInte ...

  9. VS编译环境中TBB配置和C++中lambda表达式

    TBB(Thread Building Blocks),线程构建模块,是由Intel公司开发的并行编程开发工具,提供了对Windows,Linux和OSX平台的支持. TBB for Windows ...

随机推荐

  1. CENTOS 6.5 平台离线编译安装 PHP5.6.6

    一.下载php源码包 http://cn2.php.net/get/php-5.6.6.tar.gz/from/this/mirror 二.编译 编译之前可能会缺少一些必要的依赖包,加载一个本地yum ...

  2. ElasticSearch 5学习(10)——结构化查询(包括新特性)

    之前我们所有的查询都属于命令行查询,但是不利于复杂的查询,而且一般在项目开发中不使用命令行查询方式,只有在调试测试时使用简单命令行查询,但是,如果想要善用搜索,我们必须使用请求体查询(request ...

  3. scrapy 知乎用户信息爬虫

    zhihu_spider 此项目的功能是爬取知乎用户信息以及人际拓扑关系,爬虫框架使用scrapy,数据存储使用mongo,下载这些数据感觉也没什么用,就当为大家学习scrapy提供一个例子吧.代码地 ...

  4. WebApi接口 - 响应输出xml和json

    格式化数据这东西,主要看需要的运用场景,今天和大家分享的是webapi格式化数据,这里面的例子主要是输出json和xml的格式数据,测试用例很接近实际常用情况:希望大家喜欢,也希望各位多多扫码支持和点 ...

  5. angular2系列教程(十)两种启动方法、两个路由服务、引用类型和单例模式的妙用

    今天我们要讲的是ng2的路由系统. 例子

  6. bcp 命令实例

    set sql_flow="select Id,',',ApplierName,',',FlowStatus,',',IsApproved,',',CreateTime from *** w ...

  7. iOS微信里打开app,Universal Links

    这两天在弄分享,从第三方应用或者浏览器打开自己app的东西 传统的方式是通过URL Scheme的方式,但是iOS9以后又出了新的更完美的方式Universal Links. 传统的URL Schem ...

  8. 游走 bzoj 3143

    游走(2s 128MB)walk [问题描述] [输入格式] [输出格式] [样例输入] 3 3 2 3 1 2 1 3 [样例输出] 3.333 [样例说明] 题解: 主要算法:贪心:高斯消元: 题 ...

  9. 简单酷炫的canvas动画

    作为一个新人怀着激动而紧张的心情写了第一篇帖子还请大家多多支持,小弟在次拜谢. 驯鹿拉圣诞老人动画效果图如下 html如下: <div style="width:400px;heigh ...

  10. cesium自定义气泡窗口infoWindow

    一.自定义气泡窗口与cesium默认窗口效果对比: 1.cesium点击弹出气泡窗口显示的位置固定在地图的右上角,默认效果: 2.对于习惯arcgis或者openlayer气泡窗口样式的giser来说 ...