【问题标题】:Java 8: Map instead of simple loopJava 8:映射而不是简单循环
【发布时间】:2017-01-16 14:02:18
【问题描述】:

我是 java 1.8 函数式编程的新手。 我有如下代码的简单循环:

File folder = new File("./src/renamer/Newaudio");
File[] listOfFiles = folder.listFiles();

for (int i = 0; i < listOfFiles.length; i++) {
    System.out.println("Here is file number: " + i);
}

我将使用箭头函数(如 lambda)将上面的 for loop 更改为函数格式。

listOfFiles.map((file) = > {
        System.out.println("Here is file number: " + i);
});

不幸的是,它抱怨:

Cannot invoke map((<no type> file) -> {}) on the array type File[]

为什么会出现这个错误? 我该如何解决?

我喜欢学习 Lambda,所以对 foreach 不感兴趣

【问题讨论】:

  • 使用.forEach 而不是.map。请注意,您可以使用Files.list(Paths.get("./src/renamer/Newaudio")).forEach(...) 直接跳转到Stream API。
  • 你的 lambda 中的 i 是什么?
  • 如果您使用的是 Java 8,不要使用 File。它已经过时了,应该休息一下。使用PathFiles

标签: java foreach java-8 java-stream


【解决方案1】:

您可以使用IntStream.range 仅打印文件编号

    IntStream.range(0,listOfFiles.length).forEach(System.out::println);

或要打印数组的内容,您可以使用

    Arrays.stream(listOfFiles).forEach(System.out::println);

编译器会将您的方法引用转换为 编译时的 lambda 表达式所以这个

    Arrays.stream(listOfFiles).forEach(System.out::println);

会转换成这个

=>  Arrays.stream(listOfFiles).forEach(i->System.out.println(i));

使用 lambda,您也可以使用扩展的 lambda {}

=> Arrays.stream(listOfFiles).forEach(i->{
       if (!i.isHidden()) { // don't print hidden files
           System.out.println(i);               
       }
   });

所以listFiles 返回null 是文件不是目录,为简单起见,您可以简单地把检查放在第一位

    File folder = new File("./src/renamer/Newaudio");
    if (folder.isDirectory()) {
        File[] listOfFiles = folder.listFiles();
        Arrays.stream(listOfFiles).forEach(i->System.out.println(i));           
    }

参考

Lambda and Method reference concise details

【讨论】:

  • 我喜欢学习 Lambda,所以对 foreach 不感兴趣
  • @Salman 您似乎误解了“Lambda”是什么。 lambda 是mapforEach 方法的参数,而不是map 方法本身。
【解决方案2】:

folder.listFiles() 应该用Optional.ofNullable 包裹起来,以防止出现NullPointerException。如果给定的路径名​​不表示目录,或者发生 I/O 错误,它可以返回 null

Stream.of(ofNullable(folder.listFiles()).
          orElseThrow(() -> new IllegalArgumentException("It's not a directory!")))
      .forEach(f -> {});

forEach 方法可以采用这些参数:

(1) 一个匿名类

new Consumer<File>() {
    public @Override void accept(File file) {
        System.out.println(file);
    }
}

(2) 扩展的 lambda 表达式

(File f) -> { System.out.println(f); }
(f) -> { System.out.println(f); }

(3) 简化的 lambda 表达式

f -> { System.out.println(f); }
f -> System.out.println(f)

(4) 方法参考

System.out::println

【讨论】:

  • 当我使用多行格式的 lambda (f->{system.out.pringlin()}) 它抱怨语法错误,插入“AssignmentOperator Expression”到完整表达式 - 赋值的左侧必须是变量
  • @Salman:System类以大写S开头,方法是println,而不是pringlin,语句后面必须有分号。
  • @Andrew Tobilko:forEach(不是foerEach)可以接受的参数不止这四种。实现Consumer 的命名类也可以工作,就像任何其他导致该类型实例的表达式一样,例如读取包含现有实例的变量或调用工厂方法。并且你可以传递null,编译器不会反对,尽管结果可以预见的用处不大……
【解决方案3】:
IntStream.range(0, listOfFiles.length).forEach(file -> {
    System.out.println(file);
});

【讨论】:

  • 注意:OP 的原始代码没有打印文件名,只打印了数字。
猜你喜欢
  • 1970-01-01
  • 2021-09-02
  • 1970-01-01
  • 1970-01-01
  • 2019-09-10
  • 2015-10-24
  • 2021-05-01
  • 1970-01-01
  • 2012-03-31
相关资源
最近更新 更多