本系列文章译自Venkat Subramaniam的
Functional Programming in Java
未完待续,后续文章请继续关注[url={{ site.url }}]Java译站[/url]。
<h2>第三章 字符串,比较器和过滤器</h3>
JDK引入的一些方法对写出函数式风格的代码很有帮助。JDK库里的一些的类和接口我们已经用得非常熟悉了,比如说String,为了摆脱以前习惯的那种
老的风格,我们得主动寻找机会来使用这些新的方法。同样,当我们需要用到只有一个方法的匿名内部类时,我们现在可以用lambda表达式来替换它了
,不用再像原来那样写的那么繁琐了。
本章我们会使用lambda表达式和方法引用来遍历字符串,实现Comparator接口,查看目录中的文件,监视文件及目录的变更。上一章中介绍的一些方法
还将继续出现在这里,来帮助我们更好的完成这些任务。你学到的这些新技术有助于将冗长繁琐的代码变得简洁,不仅能快速实现而且还易于维护。
<h3>遍历字符串</h3>
chars()方法是String类里的一个新方法,它是CharSequence接口的一部分。想要快速遍历String的字符序列的话,它是一个很有用的工具。有了这个>内部迭代器,我们可以方便的操作字符串中的各个字符。先用它来处理一个字符串试试。在这里顺便介绍方法引用的几种使用方式。
{% highlight java %}
final String str = "w00t";
str.chars()
.forEach(ch -> System.out.println(ch));
{% endhighlight %}
chars()方法返回的是一个Stream对象,我们可以用它的内部迭代器forEach()来进行遍历。在迭代器里,我们可以直接访问到字符串中的字符。下面是
遍历字符串并打印各个字符的输出结果。
{% highlight java %}
"_posts/2014-03-30-java-functional-programming-10.markdown" 146L, 8327C written
[root@AY140109200406026f46Z kunka]# ./generate.sh
Configuration file: /root/kunka/_config.yml
Source: /root/kunka
Destination: /usr/share/nginx/html/
Generating... done.
[root@AY140109200406026f46Z kunka]# ./convert_iteye.sh
---
layout: post
title: Java函数式编程(十)字符串及方法引用
date: 2014-03-30 08:53:31
category: Java函数式编程
keywords: 方法引用
---
本系列文章译自Venkat Subramaniam的
Functional Programming in Java
未完待续,后续文章请继续关注
Java译站。
第三章 字符串,比较器和过滤器
JDK引入的一些方法对写出函数式风格的代码很有帮助。JDK库里的一些的类和接口我们已经用得非常熟悉了,比如说String,为了摆脱以前习惯的那种老的风格,我们得主动寻找机会来使用这些新的方法。同样,当我们需要用到只有一个方法的匿名内部类时,我们现在可以用lambda表达式来替换它了,不用再像原来那样写的那么繁琐了。
本章我们会使用lambda表达式和方法引用来遍历字符串,实现Comparator接口,查看目录中的文件,监视文件及目录的变更。上一章中介绍的一些方法还将继续出现在这里,来帮助我们更好的完成这些任务。你学到的这些新技术有助于将冗长繁琐的代码变得简洁,不仅能快速实现而且还易于维护。
遍历字符串
chars()方法是String类里的一个新方法,它是CharSequence接口的一部分。想要快速遍历String的字符序列的话,它是一个很有用的工具。有了这个内部迭代器,我们可以方便的操作字符串中的各个字符。先用它来处理一个字符串试试。在这里顺便介绍方法引用的几种使用方式。
final String str = "w00t";
str.chars()
.forEach(ch -> System.out.println(ch));
chars()方法返回的是一个Stream对象,我们可以用它的内部迭代器forEach()来进行遍历。在迭代器里,我们可以直接访问到字符串中的字符。下面是遍历字符串并打印各个字符的输出结果。
119
48
48
116
这并不是我们想要的结果。我们希望看到的是字母,而输出的却是数字。这是因为chars()方法返回的是一个整型的Stream而不是字符型的。我们先了解下这个API,再去优化输出的结果。
前面的代码中我们创建了一个lambda表达式,作为forEach方法的入参。它只是简单地把参数传给了一个println()方法。由于这个操作很常见,我们可以借助Java编译器来对这段代码进行简化。就像在25页的
使用方法引用中那样,用一个方法引用来代替它,让编译器来帮我们做参数路由。
我们已经看到如何创建一个实例方法的方法引用了。比如,name.toUpperCase()方法,方法引用就是String::toUpperCase。而下面这个例子中,我们调用的是静态引用System.out的一个实例方法。方法引用的两个冒号左边,可以是一个类名或者表达式。有了这个灵活性,我们可以很容易创建一个println()方法的引用,就像下面这样。
str.chars()
.forEach(System.out::println);
可以看到,Java编译器能很聪明的完成参数的路由。回想下lambda表达式和方法引用只能出现在接收函数式接口的地方,而Java编译器会在那个地方生成一个对应的方法(译注:编译器会生成函数式接口的实现,这个实现只有一个方法)。之前我们用过的方法引用String::toUpperCase,传给那个生成方法的参数,最后会变成这个方法调用的目标对象,就像这样:parameter.toUpperCase()。这是因为这个方法引用是基于类名的(String)。而上面这个例子中的方法引用,是基于一个表达式的,它是PrintStream的一个实例,通过System.out来引用它。由于方法调用的对象已经有了,Java编译器决定用生成方法中的参数作为这个println方法的参数:System.out.println(name)。
(译注:其实主要是两种场景,同样是传递了一个方法引用,一个是把遍历的对象,当然方法调用的目标对象,比如name.toUpperCase,另外一种是作为方法调用的参数,比如System.out.println(name).)
用了方法引用之后代码简洁多了,不过我们得去深入了解下它是如何运行的。一旦我们熟悉了方法引用,就能自己想明白参数路由这些事了。
尽管这个例子中的代码已经够简洁的了,但是输出还是不如人意。我们想看到的是字母结果却出现了数字。为了解决这个问题,我们来写个方法将int输出成字母。
private static void printChar(int aChar) {
System.out.println((char)(aChar));
}
使用方法引用可以很方便的完成输出结果的优化。
str.chars()
.forEach(IterateString::printChar);
现在虽然chars()返回的结果是int,但是也无所谓了,需要打印的时候,我们会将它转化成字符。这回的输出终于是字母了。
w
0
0
t
如果我们希望从一开始就处理的就是字符而不是int,可以在调用完chars后直接将int转化成字符:
str.chars()
.mapToObj(ch -> Character.valueOf((char)ch))
.forEach(System.out::println);
这里我们用到了chars()返回的Stream的一个内部迭代器,当然能用的可不止这一个方法。拿到Stream对象后,它的那些方法就任凭我们使用了,比如map(),filter(),reduce()等。我们可以使用filter()方法来过滤出那些是数字的字符:
str.chars()
.filter(ch -> Character.isDigit(ch))
.forEach(ch -> printChar(ch));
这样输出的时候我们就只能看到数字了:
0
0
同样的,除了将lambda表达式传给filter()和forEach()方法外,我们还可以使用方法引用。
str.chars()
.filter(Character::isDigit)
.forEach(IterateString::printChar);
这里的方法引用把多余的参数路由给省掉了。在本例中,我们还看到了和前面两个方法的引用不同的用法。第一次我们引用的是一个实例方法,第二次是一个静态引用(System.out)上的方法。而这次则是一个静态方法的引用——方法引用一直在默默的付出。
实例方法和静态方法的引用看起来都一样:比方说String::toUpperCase和Character::isDigit。编译器会判断方法是实例方法还是静态方法,来决定如何路由参数。如果是实例方法,它会将生成方法的入参用作方法调用的目标对象,比如 parameter,toUpperCase();(当然也有例外,比如方法调用的目标对象已经指定了,像System::out.println())。另外如果是静态方法的话,生成方法的入参就会作为这个引用的方法的参数,比如Character.isDigit(parameter)。152页的附录2,有详细的方法引用的使用方法及语法说明。
尽管方法引用用起来很方便,但还有一个问题——方法命名冲突导致的二义性 。如果匹配的方法既有实例方法也有静态方法,由于方法存在歧义编译器会报错。比如这么写,Double::toString,我们其实是想要把一个double类型转化成字符串,但编译器就不知道到底是该调用public String toString()的实例方法好,还是去调用public static String toString(double)方法,因为两个方法都是Double类的。如果你碰到这样的情况,别灰心,就用lambda表达式来完成就好了。
一旦我们适应了函数式编程,我们就可以在lambda表达式和方法引用之间随心所欲地来回切换了。
本节中我们用了Java 8中的一个新方法来遍历字符串。下面我们来看下Comparator接口又有了哪些改进。
未完待续,后续文章请继续关注
Java译站。
原创文章转载请注明出处:
http://it.deepinmind.com
分享到:
相关推荐
Java 8是一个重要的Java语言版本,它引入了对函数式编程的支持,极大地提升了代码的简洁性和可读性,特别是对于集合操作。函数式编程是一种编程范式,它将计算视为函数的组合,而不是状态的改变或控制流程。在Java 8...
Java函数式编程是一种编程范式,它强调使用函数作为程序的基本构建块,使得代码更加简洁、可读性强且易于测试。在Java 8及其后续版本中,函数式编程得到了广泛支持,引入了lambda表达式、函数式接口以及一系列用于...
Java Lambda 函数式编程是Java 8引入的一项重要特性,它极大地简化了处理函数对象的方式,使得代码更加简洁、易读。Lambda表达式是函数式编程的核心,它允许我们将函数作为一个参数传递,或者将函数作为返回值。在这...
JAVA 8 中引入了函数式编程的概念,提供了函数式接口、Lambda 表达式和方法引用等特性。 函数式接口是 JAVA 函数式编程的核心概念。函数式接口是指只有一个抽象方法的接口。函数式接口可以被用作Lambda 表达式的...
Java函数式编程是一种编程范式,它源自数学概念,强调使用函数作为主要构造块,并避免可变状态和副作用。在Java中,从Java 8开始引入了对函数式编程的支持,特别是通过Lambda表达式和流API。让我们深入了解这个概念...
标签“使用Java8函数式编程生成字母”暗示了我们需要关注如何利用上述特性处理字符串和字符。在Java 8中,`Character`类提供了一些静态方法,如`Character.isLetter()`用于判断一个字符是否为字母,`Character....
Java 8是Java语言发展的一个重要里程碑,引入了许多新的特性,其中最为显著的当属Lambda表达式和函数式编程的支持。这些新特性极大地提升了Java在处理并发和简化代码方面的效率,使得Java更加现代化,能够更好地适应...
方法引用的概念是随着Java 8的发布引入的,它是函数式编程特性的一部分,旨在简化代码并提高可读性。本篇文章将深入探讨Java方法引用的各个方面。 首先,我们要理解什么是函数式接口。在Java中,函数式接口是指只有...
在Java函数式编程中,列表的转化是一个关键概念,它允许我们通过操作集合来转换其元素,从而生成新的集合。在本节中,我们将深入探讨如何利用Lambda表达式和Java 8中的Stream API来实现这一目标。 首先,列表的转化...
虽然Java 7没有引入Lambda,但在Java 8中,Lambda表达式极大地简化了函数式编程,使得代码更加简洁和易读。 通过深入理解上述Java 7的新特性,以及不断探索和实践Java的高级编程技术,开发者可以更好地适应行业的...
Java函数式编程中的闭包是一种强大的工具,它允许函数访问并操作其定义时的作用域内的变量,即使该函数被传递到其他上下文中。在描述的示例中,我们看到闭包是如何帮助消除代码冗余的。 当我们需要创建多个类似的...
流API的出现,让Java的代码风格更接近函数式编程,提高了代码的可读性和可维护性。 **方法引用来优化Lambda** 除了Lambda表达式,Java 8还允许使用方法引用来代替Lambda。如果Lambda体中的内容完全对应某个已有的...
Java 8的Stream API支持函数式编程,我们可以对函数数组进行操作,如映射、过滤和归约。例如,我们可以使用`map`方法将函数数组中的每个函数应用到数据源上,然后使用`collect`方法聚合结果。 6. **函数组合** ...
Java 8是Java语言的一个重要里程碑,它引入了大量的新特性,其中最为显著的就是函数式编程的支持。函数式编程是一种编程范式,强调程序执行的效果主要由纯函数决定,避免了副作用和状态变化,使得代码更易于理解和...
通过这些练习,我们不仅可以了解函数式接口的基本使用,还能掌握 Lambda 表达式和方法引用这两种简洁的代码表达方式,它们极大地提高了 Java 代码的可读性和可维护性。同时,对可变参数的理解也加深了我们对参数传递...
1. **lambda表达式**:Java 8最大的变革之一就是引入了lambda表达式,它使得函数式编程风格在Java中成为可能。Lambda表达式是一种简洁的匿名函数表示方式,可以作为方法参数,或者存储在变量中。例如,`Function, ...
### 函数式接口、方法引用相关知识点解析 #### 一、函数式接口定义与实践 ...通过上述示例,我们可以看到函数式接口和方法引用在实际编程中的应用,不仅简化了代码,也提高了代码的可读性和可维护性。
15. **Java 8及以上新特性**:lambda表达式、流API、Optional类、函数式编程等。 这份文档"最新JAVA编程题全集(50题及答案).doc"涵盖了上述众多知识点,通过解题和阅读答案,学习者可以检验自己的Java知识掌握程度...
14. **Lambda表达式**:Java 8引入的函数式编程特性,简化了匿名内部类的编写,增强了代码的简洁性和可读性。 15. **Stream API**:也是Java 8的新特性,提供了一种新的数据处理方式,使代码更简洁且易于理解。 ...
Java 8是Java平台的重大更新,引入了许多新特性,旨在提高开发效率,简化代码,并引入了函数式编程的概念。这份“Java 8编程入门学习文档”涵盖了这些关键更新,为初学者提供了丰富的学习资源。以下是一些核心知识点...