Java8学习笔记之行为参数化

行为参数化:帮助你处理频繁变更的需求的一种软件开发模式,即可以将代码块作为参数传递给另一个方法,稍后再去执行它。此时这个方法的行为就基于那块代码被参数化了。

行为参数化就是让方法接受多种行为(或战略)作为参数,并在内部使用,来完成不同的行为。 

特点:

1)可以对列表中的每个元素做“某件事”

2)可以在列表处理完后做“另一件事”

3)遇到错误时可以做“另外一件事”

示例1:实现从一个列表中筛选出绿色苹果?

实现方式有如下几种:

方式一:遍历筛选

public static List<Apple> filterGreenApples(List<Apple> list) { 

    List<Apple> result = new ArrayList<>();

    for(Apple apple: list){

        if("green".equals(apple.getColor()) result.add(apple);

    }

    return result;

}

此种方式可以实现筛选绿苹果的要求,但是如果想要筛选更多颜色的苹果就不能满足需求了,必须复制更多的filterGreenApples方法或者在循环体中增加各种if条件判断来解决,带来的问题是代码重复且复用率低,维护困难。

方式二:把颜色作为参数,适应不同颜色

public static List<Apple> filterApplesByColor(List<Apple> list, String color) {

    List<Apple> result = new ArrayList<>();

    for (Apple apple: list){

        if (apple.getColor().equals(color)) result.add(apple); 

    }

    return result;

}

此种方式可以解决颜色筛选问题,但是如果想要按重量筛选该如何处理呢?若将上述方法复制一份改为按重量过滤,则会带来代码的重复,若想更改遍历方式提升性能,就必须更改所有的方法,代价太大。

方式三:尝试对你能想到的每个属性做筛选

public static List<Apple> filterApples(List<Apple> list, String color, int weight, boolean flag) {

    List<Apple> result = new ArrayList<>();

    for (Apple apple: list){

        if ((flag && apple.getColor().equals(color)) || (!flag && apple.getWeight() > weight))

            result.add(apple);

    }

    return result;

}

此方式虽然可以解决上述需求,但是实现效果很差,并不推荐使用。如果进行组合属性或更复杂的查询,将会有多个重复的filter方法或是非常复杂的参数,维护起来会非常困难。

方式四、对选择标准建模,根据抽象条件筛选(策略模式)

你需要一种比添加很多参数更好的方法来应对变化的需求,一种可能的解决方案是对你的选择标准建模:如根据Apple的某些属性来返回一个boolean值。我们把它称为谓词(即一个返回boolean值的函数)。

定义一个接口来对选择标准建模:

public interface ApplePredicate{

    boolean test (Apple apple);

}

此时你就可以用ApplePredicate的多个实现代表不同的选择标准了,比如:

public class AppleHeavyWeightPredicate implements ApplePredicate{

    public boolean test(Apple apple){return apple.getWeight() > 150;} //筛选重量

}

public class AppleGreenColorPredicate implements ApplePredicate{

    public boolean test(Apple apple){return "green".equals(apple.getColor());} //筛选颜色

}

使用ApplePredicate改进筛选方法:

public static List<Apple> filterApples(List<Apple> list, ApplePredicate p){

    List<Apple> result = new ArrayList<>();

    for(Apple apple: inventory){

        if(p.test(apple)) result.add(apple); //谓词对象封装了测试苹果的条件

    }

    return result;

}

此时代码看起来更加简洁灵活和清晰易用了,可以方便的根据不同的条件应对不同的需求变更。例如:找出所有重量超过150克的红苹果。

public class AppleRedAndHeavyPredicate implements ApplePredicate{

    public boolean test(Apple apple){

        return "red".equals(apple.getColor()) && apple.getWeight() > 150;

    }

}

List<Apple> redAndHeavyApples = filterApples(inventory, new AppleRedAndHeavyPredicate());

filterApples方法的行为取决于你通过ApplePredicate对象传递的代码,即把filterApples方法的行为参数化了。

参数化filterApples的行为,并传递不同的筛选策略

方式五、使用匿名类

上述方式在需要把新的行为传递给filterApples方法时,你不得不声明好几个实现ApplePredicate接口的类,然后实例化多个只会用到一次的ApplePredicate对象,让代码看起来比较啰嗦。如何改进?Java有一个机制称为匿名类,它可以让你同时声明和实例化一个类,帮你改善代码变得更简洁。

通过创建一个用匿名类实现ApplePredicate的对象,重写筛选:

List<Apple> redApples = filterApples(inventory, new ApplePredicate() { //直接内联参数化 filterapples方 法的行为

    public boolean test(Apple apple){ return "red".equals(apple.getColor());}

}); 

匿名类的缺点:比较笨重,占用空间较大,其次代码不容易理解;

答案:5,this指的是包含它的Runnable,而不是外面的类MeaningOfThis。

方式六、使用Lambda表达式(推荐)

用Lambda表达式重写上述代码:

List result = filterApples(inventory,(Apple apple) -> "red".equals(apple.getColor()));

此方式代码非常简洁,看起来更像问题陈述本身,完全解决了匿名类的啰嗦问题;

方式七、将List类型抽象化(高级)

目前filterApples方法还只适用于Apple,你还可以将List类型进一步抽象化,实现处理更多的问题,如下:

public interface Predicate<T>{boolean test(T t);}

public static <T> List<T> filter(List<T> list, Predicate<T> p){ //引入泛型类型参数T

    List<T> result = new ArrayList<>();

    for(T e: list){

        if(p.test(e)) result.add(e);

    }

    return result;

}

示例2:用Comparator来排序

在Java 8中,List自带了一个sort方法(或用Collections.sort)。sort的行为可以用java.util.Comparator对象来参数化:

public interface Comparator<T> {public int compare(T o1, T o2);}

你可以创建Comparator的实现,用sort方法表现出不同的行为。比如,你可以使用匿名类,按照重量升序对库存排序:

1>普通方式

inventory.sort(new Comparator<Apple>() {

    public int compare(Apple a1, Apple a2){

        return a1.getWeight().compareTo(a2.getWeight());

    }

});

2>Lambda方式

inventory.sort( (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));

示例3:用Runnable执行代码块

Runnable接口表示一个要执行的代码块,代码不会返回任何结果 ;

public interface Runnable{public void run();}

1>普通方式

Thread t = new Thread(new Runnable() {

    public void run(){ 

        System.out.println("Hello world");

    }

});

2>Lambda方式

Thread t = new Thread(() -> System.out.println("Hello world"));

                                                                                       以上示例摘自《Java8实战》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353