`
deepinmind
  • 浏览: 450810 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
1dc14e59-7bdf-33ab-841a-02d087aed982
Java函数式编程
浏览量:41552
社区版块
存档分类
最新评论

Java函数式编程(六)查找元素

阅读更多
本系列文章译自Venkat Subramaniam的Functional Programming in Java

未完待续,后续文章请继续关注Java译站


查找元素

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

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

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


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

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

final List<String> 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<String> friends =
Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
final List<String> editors =
Arrays.asList("Brian", "Jackie", "John", "Mike");
final List<String> 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<String> 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译站


原创文章转载请注明出处:http://it.deepinmind.com




3
1
分享到:
评论

相关推荐

    Java-Java函数式编程教程

    Java函数式编程是一种编程范式,它强调使用函数作为程序的基本构建块,将计算视为函数的组合,并且尽可能避免改变状态和可变数据。在Java 8及更高版本中,函数式编程得到了官方的大力支持,引入了Lambda表达式、...

    黑马程序员Java函数式编程全套视频教程,Lambda表达式、Stream流、函数式编程一套全通关1

    Java函数式编程是一种高效、简洁的编程范式,它在Java 8中得到了全面支持,大大改变了Java开发人员编写代码的方式。本套黑马程序员的Java函数式编程视频教程涵盖了Lambda表达式、Stream流以及函数式编程的核心概念,...

    Java函数式编程(六):Optional

    Java函数式编程中的`Optional`是一个重要的工具,用于处理可能出现的缺失值,它引入了更加安全和明确的方式来处理`null`。在传统的编程中,`null`常常导致空指针异常(`NullPointerException`),而`Optional`则为...

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

    在Java函数式编程中,查找元素是处理集合时常见的任务。本文聚焦于如何在集合中高效地查找满足特定条件的元素,主要介绍`filter`方法的使用。`filter`方法是Java 8引入的Stream API的一部分,它允许我们根据提供的...

    Java 什么是函数式编程.pdf

    在Java编程中,函数式编程是一种重要的编程范式,它强调使用函数作为一等公民,即将函数视为可赋值、可传递和可存储的数据。在Java 8中,为了引入函数式编程,引入了Lambda表达式和Stream API,极大地提升了代码的...

    Java函数式编程(十一):遍历目录

    总的来说,Java函数式编程在遍历目录时提供了简洁、易读且高性能的解决方案。通过组合`Stream`操作,如`filter()`、`map()`和`forEach()`,开发者可以构建出强大的文件系统操作逻辑,同时保持代码的清晰和可维护性。...

    Java函数式编程(一):你好,Lambda表达式

    Java函数式编程,尤其是Lambda表达式,为Java开发者带来了全新的编程范式,使得代码更加简洁、易读且高效。在Java 8及更高版本中,Lambda表达式是函数式编程的核心特性之一,它允许我们将函数作为一等公民,即函数...

    Java函数速查

    - Java 8引入的lambda表达式简化了函数式编程,可以用简洁的方式表示匿名函数。 以上只是Java函数速查中涉及的部分知识点,实际的速查资源会包含更详细的函数用法、示例代码和最佳实践。通过深入学习和熟练应用...

    java函数速查中文版.rar

    Java函数速查中文版是一个非常实用的资源,对于学习和工作中快速查找Java编程中的函数用法具有很高的价值。这个压缩包文件包含了一份详尽的Java函数参考指南,它以中文形式呈现,使得中国开发者能够更加方便地理解和...

    java函数速查

    10. **Lambda表达式**:自Java 8起,引入了lambda表达式,简化了匿名函数的使用,常用于函数式编程场景。 通过"java函数速查",你可以快速查找并学习这些功能,提高编程效率。这份资料中文版的特性使得国内开发者...

    java实用编程100(1)例1-55

    9. **函数式编程**:Java 8引入了Lambda表达式,使得函数式编程风格成为可能。实例可能展示如何使用Lambda简化代码,以及流API的应用。 10. **反射机制**:Java的反射API允许程序在运行时动态获取类的信息并操作类...

    JAVA函数速查

    14. **Lambda表达式**:Java 8引入的Lambda表达式简化了函数式编程,使得代码更加简洁。 15. **注解(Annotation)**:注解为编译器和JVM提供元数据,可以用于代码分析、编译时检查或运行时处理。 通过这份Java...

    100个Java经典编程实例源代码

    12. **Lambda表达式与函数式编程**:Java 8引入了Lambda表达式,使得函数式编程风格成为可能。实例将展示如何使用它们简化代码,提高代码的简洁性和效率。 通过学习和实践这些Java编程实例,你不仅能加深对Java语言...

    java趣味编程100例

    Java的基础语法是所有编程实例的基石,包括变量声明、数据类型、运算符、流程控制(如if-else、switch、for、while循环)以及函数的使用。通过这些实例,你可以看到这些基本元素如何在实际问题中被巧妙地组合和应用...

    GDGHK-Java8:关于 Java 8 新闻和特性的研讨会和演示,以及对函数式编程的一些了解

    Lambda表达式为Java引入了函数式编程的元素,使得代码更加简洁、易读。它们可以被用来替代那些只有一个抽象方法的接口的实现,这样就可以将行为作为参数传递给方法,或者存储在变量中。Lambda表达式的语法简洁明了,...

    java教程PPT Java编程入门

    - **Lambda表达式**:简洁的函数式编程,简化回调和多线程操作。 - **Stream API**:处理集合的新方式,支持链式操作和并行流。 通过这21章的学习,初学者将能够全面理解Java语言,并具备独立编写和调试Java程序...

    Java计算机语言函数应用

    在描述中提到的API使用细节,包括了如何创建、添加元素、遍历、查找、修改和删除等操作,这些都是日常编程中常见的场景。 在学习Java函数应用时,我们通常会遇到以下关键知识点: 1. **方法重载(Overloading)**...

    java编程练习20题

    8. **函数式编程**:Java 8引入了Lambda表达式和函数式接口,题目可能要求使用这些新特性进行无副作用的编程。 9. **多线程**:Java提供了Thread类和Runnable接口来实现并发,题目可能要求编写多线程程序,理解同步...

Global site tag (gtag.js) - Google Analytics