java8新特性详解之lambda:行为参数化

行为参数化

文骚人不骚的小隐开始整理java8的新知识了。这次整理的是
java8新特性详解之lambda:行为参数化
字面意思就是把行为化为参数的过程

如何让行为参数化

来,咱们边吹边讲。今天漂亮红姐过来啦,对着我莞尔一笑说:“小隐啊,我最近想倒腾点手机,现在有一批货,帮我找一下里面的苹果手机。”美女的忙肯定要帮,而且这也就是举手之劳!

/**
* 筛选苹果手机
*/ 
public static List<Phone> screenApplePhone(List<Phone> list) throws Exception{
	if( list==null || list.size()==0 ){
        throw new Exception("参数不全");
    }
    List<Phone> resultList = new ArrayList<>();
    for (Phone phone:list) {
        if("apple".equals(phone.getBrand())){
            resultList.add(phone);
        }
    }
    return resultList;
}

齐活!像这种代码闭着眼睛都不能写错了。但是红姐虽然人美,事从来没这么容易过。这不过了不到4分钟,红姐给我说:“华为的也给我找一下我看看。”小事,有之前的代码,那还不是两个ctrl的事。秒完。

/**
* 筛选华为手机
*/ 
public static List<Phone> screenHuaWeiPhone(List<Phone> list) throws Exception{
	if( list==null || list.size()==0 ){
        throw new Exception("参数不全");
    }
    List<Phone> resultList = new ArrayList<>();
    for (Phone phone:list) {
        if("HUAWEI".equals(phone.getBrand())){
            resultList.add(phone);
        }
    }
    return resultList;
}

但是,我们知道这种做法是不可取的,因为红姐一会可能还要找中兴的、小米的、魅族的、甚至已经破产的手机厂商的手机也要找找看(天知道她会不会搞到这些手机)。如果这样的话我们慢慢就应付不了了,更加严重的是打破了DRY(Don’t Repeat Yourself,不要重复自己)的软件工程原则,在你要对这些代码进行优化的时候你也要对所有相似的进行修改,极其容易产生遗落!嘿嘿,小隐我灵机一动。

/**
* 筛选某品牌的手机
*/ 
public static List<Phone> screenPhone(List<Phone> list,String brand) throws Exception{
	if( list==null || list.size()==0 || StringUtils.isEmpty(brand)){
        throw new Exception("参数不全");
    }
    List<Phone> resultList = new ArrayList<>();
    for (Phone phone:list) {
        if(brand.equals(phone.getBrand())){
            resultList.add(phone);
        }
    }
    return resultList;
}

不过作为一个宅男,难得有美女请求帮忙,自然方方面面都要想到。可能红姐要筛选的不仅仅是品牌,还可能通过价格筛选,我们最好是提前帮她准备好方案。

    /**
     * 筛选某品牌或者低于某价格的手机
     */
    public static List<Phone> screenPhone(List<Phone> list,String brand,Integer price) throws Exception{
        if( list==null || list.size()==0 || StringUtils.isEmpty(brand)|| price==null){
            throw new Exception("参数不全");
        }
        List<Phone> resultList = new ArrayList<>();
        for (Phone phone:list) {
            if(brand.equals(phone.getBrand()) || price<(phone.getPrice())){
                resultList.add(phone);
            }
        }
        return resultList;
    }

但是这个解决方案实在是让人不敢恭维,因为随着筛选条件的增多,以及不同筛选条件的组合你的方法参数会越来越多,内容会越来越沉重。
这个时候很多人应该会想到策略设计模式,我们定义一族算法,然后把这些算法封装起来,在使用时根据不同情况使用不同算法。

   /**
     * 为筛选手机定义策略
     */
    private interface PhonePredicate{
        Boolean test(Phone phone);
    }
    private class BrandPhonePredicate implements PhonePredicate{
        @Override
        public Boolean test(Phone phone) {
            return "apple".equals(phone.getBrand());
        }
    }
    private class PricePhonePredicate implements PhonePredicate{
        @Override
        public Boolean test(Phone phone) {
            return 1000>phone.getPrice();
        }
    }
//    ......
    /**
     * 利用完策略模式后的筛选方法
     */
    public static List<Phone> screenPhone(List<Phone> list,PhonePredicate phonePredicate) throws Exception{
        if( list==null || list.size()==0 || phonePredicate == null){
            throw new Exception("参数不全");
        }
        List<Phone> resultList = new ArrayList<>();
        for (Phone phone:list) {
            if(phonePredicate.test(phone)){
                resultList.add(phone);
            }
        }
        return resultList;
    }

其实这个时候,我们的代码已经足够灵活了,每次有新的筛选需求的时候我们只要维护新的算法就能够满足需要了。不过我们可能也及其不情愿这样做,因为在使用的时候我们不得不去声明算法,尽管它可能只被实例化一次。对于这种情况java早就给出了解决办法,那就是匿名类。它允许我们随用随建。

//这里仅是方法调用部分
phones = screenPhone(list, new PhonePredicate() {
            @Override
            public Boolean test(Phone phone) {
                return "apple".equals(phone.getBrand())&&1000>phone.getPrice();
            }
        });

这样对付各种情况就很舒心了,不过代码实在是很笨重,而且可读性以比较差。并且其实我们真正使用的也只是里面的极少部分代码即作为筛选条件的代码。那么我们可不可以把这部分代码作为参数直接使用呢?答案是:不行。不过java8给我们提供了另外一种方式->lambda。写法如下:

phones = screenPhone(list,phone -> {return "apple".equals(phone.getBrand())&&1000>phone.getPrice();});

是不是爽的呀批 ^ w ^!
这种方式变相的让我们把行为作为参数传递到了方法中。不过这里要重点注意的是,我们看似传递的是行为,其实本质是对象。具体解释会在接下来的整理中。上面例子你甚至可以看做是匿名内部类的简化,但并不是语法糖。因为lambda的实现方式并不符合语法糖的定义。

最后你的筛选方法可以更改为一个更加通用的形式,让你可以筛选任何你想筛选的对象:

private interface Predicate<T>{
    Boolean test(T t);
}
public static <T> List<T> screenPhone(List<T> list,Predicate<T> predicate) throws Exception{
   if( list==null || list.size()==0 || predicate == null){
       throw new Exception("参数不全");
   }
   List<T> resultList = new ArrayList<>();
   for (T item:list) {
       if(predicate.test(item)){
           resultList.add(item);
       }
   }
   return resultList;
}

小隐小故事 ——为什么想要行为参数化

我思考了一下,为什么要行为参数化。这个确实也不是太好解释,因为就我个人感觉而言,我并不能解释的很完整或者说很准确,不过依然要记录下个人的感受,当以有了更新的理解也还是会回来重新编辑这里的内容的。
看官上座,容我喝口水开始单口相声。
话说现在这社会不仅压力大,而且节奏快,尤其是在北上广打拼的同学们,那简直就感觉每个人都在疯狂地做事。只有在深夜回到家中,在黑暗里,独自舔舐着自己的伤口。这个时候人们往往会想找个年轻人多的地方发泄一下蹦个迪神马的。
在这里插入图片描述
当然你还能想到“朋友”。这个社会其实有甚多小圈子,大家都有来往。现在交通又这么发展,其实去找朋友一趟也用不了多久。
呐你在杭州,你朋友在重庆,你买张火车票就去了。因为很多人都会从杭州到重庆,所以,坐火车这个行为咱们可以拿出来做个方法,然后给大家去使用,大家也都会去用。但是你最近认识了一个同城的妹子。
在这里插入图片描述

没有大家公认的方式去找这个朋友,而且新认识的妹子,极有可能你只会找一次就再也不会去了。原因你知道的。但是你现在还兴致勃勃的想去找她呢,你们约了今晚十点半,可是现在已经快九点了。但是你们都不慌,因为这次你不用再去走那些大家共用的步骤了。不用去订票,取票,进站,出站了。你只需要打个车,告诉司机你要去哪就行了,而且你还可以让司机路过一间店面,给朋友准备点小礼物。
而打车这种方式就不同于你坐火车那种了,必须在哪上,然后到哪,而且路都已经规划好了你只有上火车然后等着到站下车就行了。
这样看来,你打车这种就像是行为参数化。你可以肆意指挥司机路线,只要你满意,你让司机绕两圈都行。你只要是你想走的路你都可以指挥司机去走。你给司机的就是行为参数。而坐火车你就是那个对象参数,你上车,等着车到站就行(或者半路出现什么事故,抛出异常 = =)。
不过当有人多人都认识这位朋友的时候很多人去找她时出发地点一样并且路线一样的时候,这个方法还是最好提出来让大家直接调用。因为这样才能避免这个朋友换住址了,你们所有人都要把路线(也就是前面你传给司机的行为参数)改一遍。

骚磕就唠这么多,其实这只是行为参数化的冰山一角。行为参数化更多的是让代码更好的适应不断变化的需求,因为现在的甲方爸爸都是很厉害的。另外一个很重要的点就是配合在java8中同时出现的stream。行为参数化和stream在java8中是相辅相成又可以各自使用的东西。但是就目前而言他们的搭配是绝佳的。stream也将会在我整理完lamdba之后进行整理,相应的配合使用以及一些问题的解决方式也将会以栗子的方式展示。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值