Java lambda 自动推断出错
场景
ListUtil
工具类
/**
* List 的工具类
*
* @author rxliuli
*/
public class ListUtil {
/**
* 从第一个集合中过滤掉在第二个集合中的元素
* 注:比较相等性是直接使用 {@code hashCode/equals} 方法,所以集合中的元素类型 {@link T} 必须要重写这两个方法
*
* @param left 第一个集合
* @param right 第二个集合
* @param <T> 集合中元素的类型
* @return 第一个集合过滤掉第二个集合所得到的剩下的元素集合
*/
public static <T> List<T> filter(List<T> left, List<T> right) {
return left.stream()
.filter(l -> !right.contains(l))
.collect(Collectors.toList());
}
/**
* 从第一个集合中过滤掉在第二个集合中的元素
* 需要相同类型,但不需要重写 {@code hashCode/equals} 方法,直接比较函数 {@param f} 即可
* 注意:该方法的时间复杂度为 On^2,如果类型相同没有特别的需求请使用 {@link #filter(List, List)} 方法
*
* @param left 第一个集合
* @param right 第二个集合
* @param comparator 比较器,指定如何比较两个元素是否相同
* @param <T> 集合中元素的类型
* @return 第一个集合过滤掉第二个集合所得到的剩下的元素集合
*/
public static <T> List<T> filter(List<T> left, List<T> right, Comparator<T> comparator) {
return filter(left, right, (BiFunction<T, T, Boolean>) (l, r) -> comparator.compare(l, r) == 0);
}
/**
* 从第一个集合中过滤掉在第二个集合中的元素
* 不需要相同类型,也不需要重写 {@code hashCode/equals} 方法,直接比较函数 {@param f} 即可
* 注意:该方法的时间复杂度为 On^2,如果类型相同没有特别的需求请使用 {@link #filter(List, List)} 方法
*
* @param left 第一个集合
* @param right 第二个集合
* @param f 比较函数
* @param <T> 第一个集合的泛型
* @param <U> 第二个集合的泛型
* @return 第一个集合独有元素组成的列表
*/
public static <T, U> List<T> filter(List<T> left, List<U> right, BiFunction<T, U, Boolean> f) {
return left.stream()
.filter(l -> right.stream().noneMatch(r -> f.apply(l, r)))
.collect(Collectors.toList());
}
}
测试用例
@Test
public void filter3() {
class User {
private String name;
private Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public User setName(String name) {
this.name = name;
return this;
}
public Integer getAge() {
return age;
}
public User setAge(Integer age) {
this.age = age;
return this;
}
}
final List<User> users1 = Lists.newArrayList(new User("rx", 17), new User("haor", 15));
final List<User> users2 = Lists.newArrayList(new User("Ling", 15), new User("rx", 17));
//这里无法调用 getName 方法
ListUtil.filter(users1, users2, (u1, u2) -> Objects.equals(u1.getName(), u2.getName()));
}
然而吾辈无法在 lambda 中调用 getName()
方法,除非我加上类型
@Test
public void filter3() {
class User {
private String name;
private Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public User setName(String name) {
this.name = name;
return this;
}
public Integer getAge() {
return age;
}
public User setAge(Integer age) {
this.age = age;
return this;
}
}
final List<User> users1 = Lists.newArrayList(new User("rx", 17), new User("haor", 15));
final List<User> users2 = Lists.newArrayList(new User("Ling", 15), new User("rx", 17));
//声明 User 类型后就调用 getName 方法了,发生了什么?
ListUtil.filter(users1, users2, (User u1, User u2) -> Objects.equals(u1.getName(), u2.getName()));
}
明明使用了泛型,而且有类型自动推断,为什么还是要声明类型呢?
错误截图
而 IDEA 似乎认为可以直接调用,甚至都有提示
知道了问题发生的原因了,无法确定调用哪个???
那么,为什么 Comparator
和 BiFunction
两个不相干的类会有冲突呢?以及这种冲突应当如何解决呢?
嗯嗯,根据题主最新的细节,那就是啦,你有两个相同方法,两个filter方法,其实对应着这样两种调用场景
FunctionalInterface
FunctionalInterface
因为
Comparator
其实本质也是一个BiFunction
,它的函数式方法是这样的模式不就是
BiFunction
么,只是说这两个是不同的FunctionalInterface
,就像BinaryOperator
和BiFunction
类似因此当你用相同的类型
User
去调用filter方法时,两个方法其实都匹配,所以第三个参数推断不出来,只能默认是Object
类型了假设你再创建一个新类型
UserNew
,跟User
类型差不多,此时两个不同类型参数去调用filter方法,那肯定是才用第一个了,这样就不会报错了当然题主肯定会说,我也有用相同类型去调用方法1的场景啊,那就需要指明第三个参数类型
比如题主的例子,最终应该这么写
以上仅供参考(~ ̄(OO) ̄)ブ