我正面临着一个奇怪的问题

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.Collection;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
 * Created by mklueh on 13/09/2022
 */
public class Reproducer {

    private static final String COMMA_SEPARATED_STRING = "2020-05-09,hello ,10     ,11.345 ,true    ,1000000000000";

    /**
     * Not working
     */
    @Nested
    public class WithReturn {

        public String withReturn(Stream<String> stream, String delimiter, Function<? super String, String[]> tokenizer) {
            return stream.map(s -> {
                             return Arrays.stream(tokenizer != null ? tokenizer.apply(s) : s.split(delimiter))
                                          .map(String::strip) //Comment out to make it compile
                                          .collect(Collectors.toList());
                         })
                         .flatMap(Collection::stream)
                         .collect(Collectors.joining(","));
        }

        @Test
        void usingDelimiter() {
            assertEquals(COMMA_SEPARATED_STRING.replaceAll(" ", ""),
                    withReturn(Stream.of(COMMA_SEPARATED_STRING), ",", null));
        }

        @Test
        void usingTokenizer() {
            assertEquals(COMMA_SEPARATED_STRING.replaceAll(" ", ""),
                    withReturn(Stream.of(COMMA_SEPARATED_STRING), null, s -> s.split(",")));
        }
    }

    /**
     * Working
     */
    @Nested
    public class WithReturnAndStripLambda {

        public String withReturnAndStripLambda(Stream<String> stream, String delimiter, Function<? super String, String[]> tokenizer) {
            return stream.map(s -> {
                             return Arrays.stream(tokenizer != null ? tokenizer.apply(s) : s.split(delimiter))
                                          .map(s1 -> s1.strip())
                                          .collect(Collectors.toList());
                         })
                         .flatMap(Collection::stream)
                         .collect(Collectors.joining(","));
        }

        @Test
        void usingDelimiter() {
            assertEquals(COMMA_SEPARATED_STRING.replaceAll(" ", ""),
                    withReturnAndStripLambda(Stream.of(COMMA_SEPARATED_STRING), ",", null));
        }

        @Test
        void usingTokenizer() {
            assertEquals(COMMA_SEPARATED_STRING.replaceAll(" ", ""),
                    withReturnAndStripLambda(Stream.of(COMMA_SEPARATED_STRING), null, s -> s.split(",")));
        }
    }


    /**
     * Working
     */
    @Nested
    public class WithMethodExpression {

        public String withMethodExpression(Stream<String> stream, String delimiter, Function<? super String, String[]> tokenizer) {
            return stream.map(s -> Arrays.stream(tokenizer != null ? tokenizer.apply(s) : s.split(delimiter))
                                         .map(String::strip)
                                         .collect(Collectors.toList())
                         )
                         .flatMap(Collection::stream)
                         .collect(Collectors.joining(","));

    }

    @Test
    void usingDelimiter() {
        assertEquals(COMMA_SEPARATED_STRING.replaceAll(" ", ""),
                withMethodExpression(Stream.of(COMMA_SEPARATED_STRING), ",", null));
    }

    @Test
    void usingTokenizer() {
        assertEquals(COMMA_SEPARATED_STRING.replaceAll(" ", ""),
                withMethodExpression(Stream.of(COMMA_SEPARATED_STRING), null, s -> s.split(",")));
    }

  }

}

无效的方法引用

error: incompatible types: 无效的方法引用
                            .map(String::strip)
                                 ^
    method strip in class String cannot be applied to given types
      required: no arguments
      found: long
      reason: actual and formal argument lists differ in length

IntelliJ的 idea 甚至建议执行自动重构,以go 掉lambda函数而支持方法引用

enter image description here

以及用表达式lambda替换返回

enter image description here

这里出了什么问题?为什么IntelliJ建议破解代码/不承认该建议导致了编译器错误?

推荐答案

这似乎很有可能是javac个错误中的一个.IntelliJ建议的应该是一种安全的、功能相当的替代品.

看起来是JDK-8268312,在Java 20中标记为已修复.


如果不是,这里是我在摆弄你的具体例子时发现的其他一些有趣的行为:

除了方法引用失败之外,当您显式地将lambda的参数列表中的类型指定为String时,它也会失败,即String::strip变为(String sa) -> sa.trim()

这里有一个比您的更小的例子.请注意,我故意让三元的两条路径在Arrays.stream以内做完全相同的事情.我还使用了trim,因此它可以在Java 8以及更高版本的JDK上运行.

Stream.of("A").flatMap(s -> {
    return Arrays.stream(true ? s.split(",") : s.split(","))
        .map((String sa) -> sa.trim());
})
.collect(Collectors.joining(","));

出于某种原因,如果flatMap参数是一个表达式lambda,而不是一个语句lambda,那么它可以很好地编译,这应该不会对类型系统造成影响.

Stream.of("A").flatMap(s ->
    Arrays.stream(true ? s.split(",") : s.split(","))
        .map((String sa) -> sa.trim())
)
.collect(Collectors.joining(","));

如果将三元数的结果强制转换为String[],即使这已经是该表达式的类型,这也是可行的,这意味着强制转换应该是多余的.

Stream.of("A").flatMap(s -> {
        return Arrays.stream((String[]) (true ? s.split(",") : s.split(",")))
            .map((String sa) -> sa.trim());
    })
    .collect(Collectors.joining(","));

Java相关问答推荐

如何让TaskView总是添加特定的列来进行排序?

Apache POI:使用反射获取zoom 级别

Java函数式编程中的双值单值映射

滚动视图&不能在alert 对话框中工作(&Q;&Q;)

在bash中将数组作为Java程序的参数传递

当涉及到泛型时,类型推理在Java中是如何工作的?

如何正确创建序列图?

Kotlin内联互操作:强制装箱

当返回Mono<;Something>;时,不会调用Mono<;void>;.flatMap

与Spring Boot相关的实体未正确保存

如何使用路径过渡方法使 node 绕圆旋转?

如何使用Criteria Builder处理一对多关系中的空值?

将stringBuilder + forloop转换为stream + map

JOLT根据值删除并保留其余的json键

未调用OnBackPressedCallback-Activitiy立即终止

为什么我的登录终结点不能被任何请求访问?

如何在特定关键字后提取与模式匹配的多个值?

如何在单元测试中获得我的装饰Mapstruct映射器的实例?

ControlsFX RangeSlider在方向垂直时滞后

类型安全:从 JSONArray 到 ArrayList> 的未经判断的转换