Java Stream使用String::length报错原因及正确写法咨询
先明确前提:people是List<Person>类型的集合,流中的元素是Person对象。
第一个代码片段报错:Non-static method cannot be referenced from a static context
people.stream() .mapToInt(String::length) .forEach(System.out::println);
mapToInt需要的是ToIntFunction<Person>,也就是能接收Person对象并返回int的函数。而String::length是String类的实例方法,调用它必须依赖一个String对象。这里直接把它传给mapToInt,编译器会误以为你要把它当作静态方法(不需要实例就能调用)来使用,但length()根本不是静态方法,因此抛出“非静态方法不能从静态上下文引用”的错误。本质是流元素类型(Person)和方法引用所需的实例类型(String)不匹配,且错误地试图以静态方式调用实例方法。
第二个代码片段报错:reason: no instance(s) of type variable(s) exist so that Person conforms to String
people.stream() .map(String::length) .forEach(System.out::println);
map方法要求传入的Function必须能接收流中的元素类型(Person),并返回另一种类型。但String::length对应的Function是接收String、返回int的,流里的元素是Person,无法直接适配成String类型,编译器找不到合适的类型转换规则,因此报错。
第三个代码片段能正常执行
people.stream() //.map(Main.Person::toString) //.mapToInt(String::length) .mapToInt(person->person.toString().length()) .forEach(System.out::println);
这个lambda表达式person->person.toString().length()的逻辑是:先调用Person的toString()方法把对象转成String,再调用String的length()方法获取长度。这完全符合ToIntFunction<Person>的要求——接收Person,返回int。
注释里的写法也是可行的:先通过map(Main.Person::toString)把Person流转换成String流,此时再调用mapToInt(String::length)就没问题了,因为流元素已经是String,String::length作为实例方法引用,会自动绑定每个String对象调用length(),完美匹配ToIntFunction<String>的需求。
总结:方法引用的使用必须严格匹配流元素的类型和方法的参数/实例要求,不能直接跨类型使用不匹配的方法引用。
内容的提问来源于stack exchange,提问作者Sabo

