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

语法部分就不写了,我们直接抛出一个实际问题,看看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的另一大利器

 

转载于:https://www.cnblogs.com/crackAn/p/6246953.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值