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

列出目录中的文件

用File类的list()方法可以很容易的列出目录中的所有文件的文件名。如果想要获取文件而不止是文件名的话,可以使用它的listFiles()方法。这很简单,难的是怎么去处理这个返回的列表。我们不再使用传统的冗长的外部迭代器,而是使用优雅的函数式来实遍历这个列表。这里我们还得用到JDK的新的CloseableStream接口以及一些相关的高阶函数。

下面这段代码可以列出当前目录下所有文件的名字。

复制代码 代码如下:

Files.list(Paths.get("."))
     .forEach(System.out::println);

如果想列出别的目录的话,可以把”.”替换成想要访问的目录的完整路径。

这里先是使用了Paths的get()方法,通过一个字符串创建了一个Path实例。然后通过Files工具类的list()方法获取到了一个ClosableStream对象,我们可以用它来遍历目录下的所有文件。然后我们使用内部迭代器forEach()来打印出文件名。我们先来看下这段代码的部分输出结果:列出当前目录下的文件及子目录。

复制代码 代码如下:

./aSampleFiles.txt
./bin
./fpij
...

如果我们只想获取当前目录的子目录,而不要文件的话,可以使用filter()方法:

复制代码 代码如下:

Files.list(Paths.get("."))
     .filter(Files::isDirectory)
     .forEach(System.out::println);

ilter()方法将目录从文件流中筛选出来。我们把Files类的isDirectory方法的引用传了进去,而不是传递一个lambda表达式。回想下filter()方法它需要的是一个返回boolean值的Predicate类型,这个方法正好合适。最后我们用一个内部迭代器来打印出目录的名字。程序将会打印出当前目录的子目录。

复制代码 代码如下:

./bin
./fpij
./output
...

这样写简单多了,跟Java老的写法相比省了不少代码。下面我们来看下如何列出匹配某个模式的文件。

列出目录下指定的文件

Java很早前就提供了一个list()方法的变种,用来筛选文件名。这个版本的list()方法接受一个FilenameFilter类型的参数。这个接口只有一个accept()方法,它接受两个参数:File dir(代表目录),以及String name(代表文件名)。accept()方法返回true的话这个文件名就会出现在返回的列表中,返回false则不在。我们来实现一下这个方法。

习惯性的做法是将一个实现了FilenameFilter接口的匿名内部类的实例传给list()方法。比如说,我们来看下如何用这种方式来返回fpij目录下的.java文件。

复制代码 代码如下:

final String[] files =
new File("fpij").list(new java.io.FilenameFilter() {
public boolean accept(final File dir, final String name) {
return name.endsWith(".java");
}
});
System.out.println(files);

这着实得费些工夫写几行代码。这样的代码太聒噪了:创建对象,调用函数,定义匿名内部类,在类里面嵌入方法等等。我们不用再忍受这样的痛苦了,只需传一个接受两个参数并返回bollean的lambda表达式进去就好了。Java编译器会搞定剩下的事。

前面那个例子可以简单的用一个lambda表达式替换掉匿名内部就好了,但是还有进一步优化的空间。新的DirectoryStream工具可以帮助我们更高效的遍历大的目录结构。我们来试下这种方法。这是newDirectoryStream()方法的一个变种,它接受一个额外的过滤器。

复制代码 代码如下:

Files.newDirectoryStream(
      Paths.get("fpij"), path -> path.toString().endsWith(".java"))
     .forEach(System.out::println);

这样我们去掉了匿名内部类并把繁琐的代码变得简洁明了。这两个版本的输出结果是一样的。我们来打印下指定的文件。

这段代码只会输出指定目录下的.java文件,下面是它的部分输出结果:

复制代码 代码如下:

fpij/Compare.java
fpij/IterateString.java
fpij/ListDirs.java
...

我们基于文件名来筛选文件,同样也可以很容易通过文件属性,比如文件是不是可执行文件,是否可读,可写等来进行筛选。这么做的话得需要一个listFiles()方法,它接受一个FileFilter类型的参数。我们仍然使用lambda表达式来实现而不是去创建匿名内部类。现在来看一个列出当前目录下所有隐藏文件的例子。

复制代码 代码如下:

final File[] files = new File(".").listFiles(file -> file.isHidden());

如果我们操作的是一个很大的目录,可以使用DirectoryStream而不是直接调用File上面的方法。

我们传给listFiles()方法的lambda表达式的签名和FileFilter接口的accept()方法的签名是一样的。这个lambda表达式接受的是一个File实例的参数,在这个例子中参数名是file。如果文件是隐藏属性的话,刚返回true,否则返回false.

这里其实还可以再精简下代码,我们不传lambda表达式了,传一个方法引用会让代码看起来会更简洁一些 :

复制代码 代码如下:

new File(".").listFiles(File::isHidden);

我们先用lambda表达式实现,随后又使用方法引用将它重构得更加简洁。如果我们再写新的代码的话,当然应该采用这种简洁的方式。如果可以早点发现这种简洁的实现,我们当然要优先使用它。有一句话叫做”先让它能工作,然后再去优化(make it work, then make it better)",先让代码能跑起来,等我们理清楚了,才去考虑简洁性和性能等进行优化。

我们通过一个例子来从目录中过滤出了指定的文件。下面我们来看下如何去遍历指定目录下的子目录。

时间: 2024-09-02 21:18:39

Java函数式编程(十一):遍历目录_java的相关文章

Java函数式编程(五):闭包_java

使用词法作用域和闭包 很多开发人员都存在这种误解,认为使用lambda表达式会导致代码冗余,降低代码质量.恰恰相反,就算代码变得再复杂,我们也不会为了代码的简洁性而在代码质量上做任何妥协,下面我们就会看到. 在前面一个例子中我们已经可以重用lambda表达式了;然而,如果再匹配另外一个字母,代码冗余的问题很快又卷土重来了.我们先来进一步分析下这个问题,然后再用词法作用域和闭包来把它解决掉. lambda表达式带来的冗余 我们来从friends中过滤出那些以N或者B开头的字母.继续延用上面的那个例

Java函数式开发 Optional空指针处理_java

摘要 空闲时会抽空学习同在jvm上运行的Groovy和Scala,发现他们对null的处理比早期版本Java慎重很多.在Java8中,Optional为函数式编程的null处理给出了非常优雅的解决方案.本文将说明长久以来Java中对null的蹩脚处理,然后介绍使用Optional来实现Java函数式编程. 那些年困扰着我们的null 在Java江湖流传着这样一个传说:直到真正了解了空指针异常,才能算一名合格的Java开发人员.在我们逼格闪闪的java码字符生涯中,每天都会遇到各种null的处理,

Java函数式编程(八):字符串及方法引用_java

第三章 字符串,比较器和过滤器 JDK引入的一些方法对写出函数式风格的代码很有帮助.JDK库里的一些的类和接口我们已经用得非常熟悉了,比如说String,为了摆脱以前习惯的那种老的风格,我们得主动寻找机会来使用这些新的方法.同样,当我们需要用到只有一个方法的匿名内部类时,我们现在可以用lambda表达式来替换它了,不用再像原来那样写的那么繁琐了. 本章我们会使用lambda表达式和方法引用来遍历字符串,实现Comparator接口,查看目录中的文件,监视文件及目录的变更.上一章中介绍的一些方法还

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

第一章 你好,lambda表达式! 第一节 Java的编码风格正面临着翻天覆地的变化. 我们每天的工作将会变成更简单方便,更富表现力.Java这种新的编程方式早在数十年前就已经出现在别的编程语言里面了.这些新特性引入Java后,我们可以写出更简洁,优雅,表达性更强,错误更少的代码.我们可以用更少的代码来实现各种策略和设计模式. 在本书中我们将通过日常编程中的一些例子来探索函数式风格的编程.在使用这种全新的优雅的方式进行设计编码之前,我们先来看下它到底好在哪里. 改变了你的思考方式 命令式风格--

Java函数式编程(三):列表的转化_java

列表的转化 将集合转化成一个新的集合就和遍历它一样简单.假设我们要将列表中的名字转化成全大写的.我们看下都有哪些实现方式. Java中的字符串是不可变的,所以它没法改变.我们可以生成新的字符串,用来替换列表中原有的元素.然而这样做的话,原来列表就没了;还有一个问题,原来的列表可能也是不可变的,比如Arrays.asList()生成的,所以修改原来的列表这招不行.还有一个缺点就是这样做很难并行操作. 生成一个新的全大写的列表是个不错的选择. 乍听起来这个建议弱爆了;性能是我们都很关注的一个问题.令

Java函数式编程(二):集合的使用_java

第二章:集合的使用 我们经常会用到各种集合,数字的,字符串的还有对象的.它们无处不在,哪怕操作集合的代码要能稍微优化一点,都能让代码清晰很多.在这章中,我们探索下如何使用lambda表达式来操作集合.我们用它来遍历集合,把集合转化成新的集合,从集合中删除元素,把集合进行合并. 遍历列表 遍历列表是最基本的一个集合操作,这么多年来,它的操作也发生了一些变化.我们使用一个遍历名字的小例子,从最古老的版本介绍到现在最优雅的版本. 用下面的代码我们很容易创建一个不可变的名字的列表: 复制代码 代码如下:

Java函数式编程(七):MapReduce_java

译注:map(映射)和reduce(归约,化简)是数学上两个很基础的概念,它们很早就出现在各类的函数编程语言里了,直到2003年Google将其发扬光大,运用到分布式系统中进行并行计算后,这个组合的名字才开始在计算机界大放异彩(那些函数式粉可能并不这么认为).本文我们会看到Java 8在摇身一变支持函数式编程后,map和reduce组合的首次亮相(这里只是初步介绍,后续还会有针对它们的专题). 对集合进行归约 现在为止我们已经介绍了几个操作集合的新技巧了:查找匹配元素,查找单个元素,集合转化.这

基于范型的java函数式编程(一)

编程|函数 注:在您阅读本篇的时候,希望你对Java Generic(范型)能够有所了解和明白. 记:周末在给javaparty讲FP中,很多人似乎对fp并不关心,也认为java中fp的作用不大.其实这是个很大的观念错误,范型的发展,对java的函数式编程支持很大,对Functor的影响也非常大.Functor在算法.逻辑.条件计算.规则引擎等等方面,都会有很大的作为,这个影响可就会深远的多了.-- 估且以此篇的开端,唤醒java开发者对FP in Java的重新认识. 周六给javaparty

JAVA语言编程格式高级规范_java

作为一位开发人员,都要有严格的代码规范.为此我总结了一些代码规范案例. 目 录 1. 前言 2. 试用范围 3. JAVA命名规范-- 3.1 公共约定 3.2 Java文件.包 3.3 类.接口命名规范 3.4 方法命名规范 3.5 常量 3.6 变量和参数 3.7 组件/部件 3.8 集合 3.9 神秘的数 3.10 其他 3.11 Java异常 3.12 数组命名 3.13 数据库表命名规则 3.14 数据库字段命名规则 3.15 JSP文件命名 3.16 Servlet类命名 4. 书写