简体   繁体   中英

method in class String cannot be applied to given types when replacing lambda with method reference in JDK 11

I'm facing an odd issue

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(",")));
    }

  }

}

invalid method reference

error: incompatible types: invalid method reference
                            .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

And the IntelliJ IDEA even recommends to perform the auto-refactoring to get rid of the lambda function in favor of the method reference

在此处输入图像描述

as well as replacing the return with expression lambda

在此处输入图像描述

What is wrong here and why does IntelliJ recommend to break code / not recognize that the recommendation is causing compiler errors?

This seems very likely to be a bug in javac . What IntelliJ is suggesting should be a safe and functionally equivalent replacement.

Looks to be accounted for by JDK-8268312 , which is marked as fixed in Java 20.


In case it's not, here's some other interesting behaviour I found when fiddling with your specific example:

In addition to failing for method references, it also fails when you explicitly specify the type in the lambda's parameter list as String , ie String::strip becomes (String sa) -> sa.trim()

Here's a more minimal example than yours. Note that I intentionally made both paths of the ternary within Arrays.stream do the exact same thing. I also used trim so this can be run on Java 8, as well as later JDKs.

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

For some reason, it compiles fine if the flatMap argument is an expression lambda, rather than a statement lambda, which should not make a difference to the type system.

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

It also works if you cast the result of the ternary to String[] , even though that's already the type of that expression, meaning the cast should be redundant.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM