【问题标题】:Java 8 Streams:Why does mapToInt needs the Integer::parseInt as a parameter?Java 8 Streams:为什么 mapToInt 需要 Integer::parseInt 作为参数?
【发布时间】:2019-07-06 11:14:28
【问题描述】:

我正在尝试按照下一个示例理解一些内容:

    Stream.of("a1", "a2", "a3")
            .map(s -> s.substring(1))
            .mapToInt(Integer::parseInt)
            .max()

     . (etc.)

为什么 mapToInt 需要

    Integer::parseInt 

作为参数?它不应该是隐含的吗?这个参数是不是多余的?

【问题讨论】:

  • 您可以提供任何返回intInteger 的方法,我猜,但如果您正在流式传输Strings 的数组,那么Integer.parseInt 似乎是最佳选择。 .
  • Stream#mapToInt 方法采用IntFunction任意类型(不仅仅是String)映射到int。该方法还返回一个IntStream,它是一个专用于int 的流。为什么你认为这个IntFunction 参数可能是隐含的?
  • 如果你有List<Car>,而每辆车都有car.getAmountOfDors(),你想创建int[] dors?你会如何为它写流?应该在??? 中放置什么以使int[] dors = cars.stream().???.toArray(); 工作?

标签: java java-8 java-stream


【解决方案1】:

区分调用 Stream#mapToInt(ToIntFunction)ToIntFunction 参数的作用很重要。

  • mapToInt 的调用是流将要执行的操作(即将元素映射到int)。
  • ToIntFunction 参数是流将如何将每个元素映射到int

他们是否可以包含一个无参数的mapToInt 方法,该方法将Strings 隐式解析为ints?是的,但是look at how well that works for Stream#sorted()——这种情况远没有无参数mapToInt 方法那么任意或模棱两可。

无参数sorted 方法假定元素是Comparable,这是Java 中一个基本的、标准化的和广泛传播的接口——任何类都可以实现该接口(而只有一个类可以是@987654341 @)。因此,虽然该方法不是类型安全的,但可以说用例足够普遍,足以证明其存在是合理的。

但是,假定元素为 Strings 并将其内容解析为 int 的无参数 mapToInt 方法是一个高度特定的用例。为什么如此通用的 API 会提供如此具体的操作?这将是一个完全武断的决定,没有合理的理由。例如,为什么不将每个String 映射到它的length 呢?为什么String 被特别处理而不是其他类型?因此,该方法接受一个ToIntFunction 参数,该参数描述如何根据具体情况将元素映射到int


注意Integer::parseInt 是一个method reference 可能会有所帮助,它是一个琐碎的lambda expression 的简写。两者都是functional interface 的实现,它比使用anonymous class 更简洁。换句话说,您正在创建一个新的 ToIntFunction 实例并将其作为参数传递。

以下所有功能在功能上都是等效的:

// method reference
stream.mapToInt(Integer::parseInt)

// lambda expression
stream.mapToInt((String value) -> Integer.parseInt(value)) // explicit parameter types
stream.mapToInt(value -> Integer.parseInt(value))          // implicit parameter types

// anonymous class
stream.mapToInt(new ToIntFunction<>() {

    @Override
    public int applyAsInt(String value) {
        return Integer.parseInt(value);
    }

})

其中streamStream&lt;String&gt;

【讨论】:

    【解决方案2】:

    这不是多余的。您需要说明如何将字符串“1”转换为整数 1。

    (我猜你可能会争辩说,一个无参数的 mapToLong 方法会很方便,但设计者并没有在 API 中包含一个。)


    我猜你也可能会问为什么要费心进行显式整数转换。

    如果您尝试将Stream::max 应用于数字表示为字符串的流,您将获得词汇上的最大值,而不是数字上的最大值。例如“9”大于“11”。

    请注意,Stream::max 方法没有没有参数的重载。您需要提供一个比较器;例如

    Stream.of("a1", "a2", "a3")
        .map(s -> s.substring(1))
        .max(compareAsIntegers)
    

    在哪里

    Comparator<String> compareAsIntegers = new Comparator<String>() {
        public int compare (String s1, String s2) {
            return Integer.compare(Integer.parseInt(s1),
                                   Integer.parseInt(s2));
        }
    }
    

    【讨论】:

    • 您可以简单地将Comparator.comparingInt(Integer::parseInt) 用作Comparator。但我不明白那个假设的“无参数mapToLong 方法”应该做什么。
    【解决方案3】:

    你正在做的操作是这样的:

    Stream.of("a1", "a2", "a3")           //step1
            .map(s -> s.substring(1))     //step2
            .mapToInt(Integer::parseInt)  //step3
            .max()
    

    您定义了一个字符串流(在第 1 步中),然后您将其中的每一个都丢弃在其上的 1 个字符留下“1”、“2”和“3”的流,(第 2 步)但请注意那些仍然是字符串对象... 然后你把它转换成整数,因此你需要给'mapToInt'一个“函数”,它接受一个字符串作为参数并返回一个整数(步骤3)

    这是在 Integer 类中定义的:

    https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#parseInt(java.lang.String)

    您当然可以编写并传递您自己的函数...但是为什么要重新发明轮子呢? :)

    【讨论】:

      【解决方案4】:

      substring 返回一个字符串而不是整数。 mapToInt 将对象流(在本例中为字符串)转换为 IntStream int 原语。但是它不知道如何进行映射,您需要为其提供一个函数,在您的情况下为parseInt

      【讨论】:

      • 不,parseInt 不返回 Integer 对象; valueOf 确实如此。 parseInt 返回一个原语 int
      【解决方案5】:

      实际上,在阅读了这里的友好答案后,我明白了 1. 我的问题不够清楚。 2.答案...

      所以,

      1. 我真正的意思是 - 不是将 Integer::parseInt 作为参数传递给 mapToInt 是多余的吗?因为我觉得 mapToInt 准确地描述了该方法的目的 - 将对象映射到 int,并且添加 parseInt 是不必要的,因为它实际上是相同的 - 将对象解析为 int...

      2. 但后来我尝试传递 Integer:valueOf 并且它也被接受了 - 所以我知道有几个选项可以传递给 mapToInt,这回答了我的问题...

      【讨论】:

      • 谢谢!如果您愿意,我很乐意接受您的 cmets 作为答案!
      • Integer::valueOf 是一个不好的例子,因为它仍然与Integer::parseInt 相同,但在这种情况下进行了不必要的装箱和拆箱。考虑像@​​987654323@ 这样的例子,它将String 转换为int,做一些完全不同的事情。并且泛型类 Stream 没有内置方法将其元素转换为 int 假设它们始终是 String 实例...
      【解决方案6】:

      1)mapToInt 函数的主要目的是将当前流转换为 Intstream,在其上可以执行其他 Integer 操作,如 sum、Min、max 等。

      1. 它是泛型,你永远无法预测输入是什么,在你的情况下它是 String,它可能是 double ,long 或其他东西。 由开发人员来处理显式转换。

      2. 您可以编写自己的函数,在这种情况下它是 function,它只不过是作为 mapToInt func 的参数的 ToIntFunction。 您可以重写自己的函数式接口,例如 function ,但在这里您还需要在函数 applyAsInt 内执行 parseInt,但这将是一次性工作,您可以在进行某些其他类似调用时重复使用。

      【讨论】:

        猜你喜欢
        • 2010-12-12
        • 2011-09-30
        • 2011-07-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多