当前位置:  编程技术>java/j2ee

Java函数式编程(四):在集合中查找元素

    来源: 互联网  发布时间:2014-11-08

    本文导语:  查找元素 现在我们对这个设计优雅的转化集合的方法已经不陌生了,但它对查找元素却也是无能为力。不过filter方法却是为这个而生的。 我们现在要从一个名字列表中,取出那些以N开头的名字。当然可能一个也没有,结果可...

查找元素

现在我们对这个设计优雅的转化集合的方法已经不陌生了,但它对查找元素却也是无能为力。不过filter方法却是为这个而生的。

我们现在要从一个名字列表中,取出那些以N开头的名字。当然可能一个也没有,结果可能是个空集合。我们先用老方法实现一把。

代码如下:

final List startsWithN = new ArrayList();
for(String name : friends) {
if(name.startsWith("N")) {
startsWithN.add(name);
}
}

这么简单的事件,写了这么多代码,也够啰嗦的了。我们先创建了一个变量,然后把它初始为一个空集合。然后遍历原来的集合,查找那些以指定字母开头的名字。如果找到,就插入到集合里。

我们用filter方法来重构一下上面这段代码,看看它的威力到底如何。

代码如下:

final List startsWithN =
friends.stream()
.filter(name -> name.startsWith("N"))
.collect(Collectors.toList());

filter方法接收一个返回布尔值的lambda表达式。如果表达式结果为true,运行上下文中的那个元素就会被添加到结果集中;如果不是,就跳过它。最终返回的是一个Steam,它里面只包含那些表达式返回true的元素。最后我们用一个collect方法把这个集合转化成一个列表——在后面52页的使用collect方法和Collecters类中,我们会对这个方法进去更深入的探讨。

我们来打印一下这个结果集中的元素:

代码如下:

System.out.println(String.format("Found %d names", startsWithN.size()));

从输出结果很明显能看出来,这个方法把集合中匹配的元素全都找出来了。
代码如下:

Found 2 names

filter方法和map方法一样,也返回了一个迭代器,不过它们也就这点相同而已了。map返回的集合和输入集合大小是一样的,而filter返回的可不好说。它返回的集合的大小区间,从0一直到输入集的元素个数。和map不一样的是,filter返回的是输入集的一个子集。

到现在为止,lambda表达式带来的代码简洁性让我们很满意,不过如果不注意的话,代码冗余的问题就开始慢慢滋长了。下面我们来讨论下这个问题。

lambda表达式的重用

lambda表达式看起来很简洁,实际上一不小心很容易就出现代码冗余了。冗余会导致代码质量低下,难以维护;如果我们想做一个改动,得把好几处相关的代码都一起改掉才行。

避免冗余还可以帮忙我们提升性能。相关的代码都集中在一个地方,这样我们分析它的性能表现,然后优化这一处的代码,很容易就能提升代码的性能。

现在我们来看下为什么使用lambda表达式容易导致代码冗余,同时考虑如何去避免它。

代码如下:

final List friends =
Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
final List editors =
Arrays.asList("Brian", "Jackie", "John", "Mike");
final List comrades =
Arrays.asList("Kate", "Ken", "Nick", "Paula", "Zach");
We want to filter out names that start with a certain letter.

我们希望过滤一下某个字母开头的名字。先用filter方法简单地实现一下。
代码如下:

final long countFriendsStartN =
friends.stream()
.filter(name -> name.startsWith("N")).count();
final long countEditorsStartN =
editors.stream()
.filter(name -> name.startsWith("N")).count();
final long countComradesStartN =
comrades.stream()
.filter(name -> name.startsWith("N")).count();

lambda表达式让代码看起来很简洁,不过它不知不觉的带来了代码的冗余。在上面这个例子中,如果想改一下lambda表达式,我们得改不止一处地方——这可不行。幸运的是,我们可以把lambda表达式赋值给变量,然后对它们进行重用,就像使用对象一样。

filter方法,lambda表达式的接收方,接收的是一个java.util.function.Predicate函数式接口的引用。在这里,Java编译器又派上用场了,它用指定的lambda表达式生成了Predicate的test方法的一个实现。现在我们可以更明确的让Java编译器去生成这个方法,而不是在参数定义的地方再生成。在上面例子中,我们可以明确的把lambda表达式存储到一个Predicate类型的引用里面,然后再把这个引用传递给filter方法;这样做很容易就避免了代码冗余。

我们来重构前面这段代码,让它符合DRY的原则吧。(Don't Repeat Yoursef——DRY——原则,可以参看The Pragmatic Programmer: From Journeyman to Master[HT00],一书)。

代码如下:

final Predicate startsWithN = name -> name.startsWith("N");
final long countFriendsStartN =
friends.stream()
.filter(startsWithN)
.count();
final long countEditorsStartN =
editors.stream()
.filter(startsWithN)
.count();
final long countComradesStartN =
comrades.stream()
.filter(startsWithN)
.count();

现在不用再重复写那个lambda表达式了,我们只写了一次,并把它存储到了一个叫startsWithN的Predicate类型的引用里面。这后面的三个filter调用里,Java编译器看到在Predicate伪装下的lambda表达式,笑而不语,默默接收了。

这个新引入的变量为我们消除了代码冗余。不过不幸的是,后面我们就会看到,敌人很快又回来报仇雪恨了,我们再看看有什么更厉害的武器能替我们消灭它们。


    
 
 

您可能感兴趣的文章:

  • java的数学函数在那个类中,如幂函数、指数、对数、双曲线函数等?
  • 怎样用JAVA函数读写注册表,有这样的函数吗
  • java 的条件判断函数(类似于别的语言iif函数)
  • PHP中的Pack()函数,Java有哪个函数与之对应???
  • JAVA中函数调用时,能不能向 C/C++一样函数的入口参数可以为传出值(就是引用,或指针)
  • 急!请问有分析java程序性能瓶颈的工具吗?例如,统计 java 程序中函数调用次数?
  • 请问在JAVA里将小写字母换为大写字母是用什么函数,大写转成小写又是用哪个函数?
  • java里有什么函数可以检查 java 代码并执行它?
  • 谁能告诉我,在JAVA中,哪个函数和ASP中的Int()函数等同,也就是取整函数
  • java类中的方法就是函数了,函数参数全是传值了,传址参数怎样表示?
  • 虚函数与纯虚函数(C++与Java虚函数的区别)的深入分析
  • Java中有不有与VB中Replace函数功能类似的函数?
  • java中函数的缺省参数怎么定义?
  • 如何实现Java下的回调函数!
  • 有关Java构造函数的问题之一——缺省性
  • 关于java函数?
  • ******关于java中调用函数的问题********
  • ▲ JAVA函数大全!!! ▲
  • JAVA里有没有类似SLEEP的函数?
  • Java函数式编程 Funcito
  • Java有没有集合的概念
  • Java 实时集合框架 Javolution
  • Java集合工具包 lambdaj
  • java集合框架 hppc
  • Java集合框架 fastutil
  • Java集合类 GNU Trove
  • Java高性能集合类 ConcurrentLinkedHashMap
  • java去除集合中重复元素示例分享 java去除重复
  • 用java做一个“求集合子集的”算法。
  • java集合map取key使用示例 java遍历map
  • java实现高效的枚举元素集合示例
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 还发一个查找文件的贴子,给一个相对目录USR0怎样用JAVA查找其下的文件
  • java 折半查找法(二分查找)实例
  • 查找Java类的网站 findjar
  • 在JAVA里面查找文件,用什么命令?
  • java 里有没有可以查找文件的类
  • java运行时查找工具 ClassGrep
  • java二分查找插入法
  • 在JAVA中如何实现在一个长字符串查找某个字符串??
  • 在jsp或java中有没有查找子串在父串中位置的通用方法?
  • 各位高手:java中查找字符串并替换用什么方法?
  • java中有没有这样的函数就是判断一个字符串里面是不是含有另外一个字符串!例如 abcdef 里面查找是不是含有de谢谢了~初学者
  • java实现查找文本内容替换功能示例
  • android用java和c实现查找sd卡挂载路径(sd卡路径)的方法
  • java命名空间java.sql类types的类成员方法: java_object定义及介绍
  • 我想学JAVA ,是买THINK IN JAVA 还是JAVA2核心技术:卷1 好???
  • java命名空间java.awt.datatransfer类dataflavor的类成员方法: imageflavor定义及介绍
  • 请问Java高手,Java的优势在那里??,Java主要适合于开发哪类应用程序
  • java命名空间java.lang.management类managementfactory的类成员方法: getcompilationmxbean定义及介绍
  • 如何将java.util.Date转化为java.sql.Date?数据库中Date类型对应于java的哪个Date呢
  • java命名空间java.lang.management接口runtimemxbean的类成员方法: getlibrarypath定义及介绍
  • 谁有电子版的《Java编程思想第二版(Thinking in java second)》和《Java2编程详解(special edition java2)》?得到给分
  • java命名空间java.lang.management接口runtimemxbean的类成员方法: getstarttime定义及介绍
  • 本人想学java,请问java程序员的待遇如何,和java主要有几个比较强的方向
  • java命名空间java.awt.datatransfer类dataflavor的类成员方法: stringflavor定义及介绍
  • 我对JAVA一窍不通,可惜别人却给我一个Java的project,要我做一个安装程序,请问哪里有JAVA INSTALLER下载,而且我要不要安装java的sdk才能完成此项任务?
  • java命名空间java.security类keystore的类成员方法: getdefaulttype定义及介绍
  • 新年第一天,让我们讨论一下未来一年JAVA的发展趋势! 个人认为,JAVA将主要朝ERP和JAVA手机方面发展!
  • java命名空间java.lang.management接口runtimemxbean的类成员方法: getclasspath定义及介绍
  • 我想学Java,但不知道Java的实用的开发工具有那些,Java主要用在哪些方面,EJB到底是什么东西??
  • java命名空间java.awt.datatransfer类dataflavor的类成员方法: javaserializedobjectmimetype定义及介绍
  • redhat7.3下,java程序打印中文直接用java命令执行正常,用crontab执行java命令为乱码


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3