提问人:JayC667 提问时间:11/14/2023 最后编辑:user207421JayC667 更新时间:11/14/2023 访问量:80
“Lambdas”与“泛型”问题的优雅解决方案?
Elegant solution to the "Lambdas" vs "Generics" problem?
问:
我在这里寻找一个更漂亮的解决方案。问题在于将泛型表达式和 Lambda 表达式组合在一起。
根据 Java 语言规范,这不可能以我想要的方式进行。
所以我要问你一个问题:你知道处理这个问题的更优雅的方法吗?有什么建议或常见做法吗?
我的“List”类,我需要很多函数:BiPredicate<T, T>
package stackoverflow.genericlambdas;
import java.util.ArrayList;
import java.util.function.BiPredicate;
public class MyListImpl<T> {
private final ArrayList<T> mItems = new ArrayList<>();
public void addItem(final T pItem) {
mItems.add(pItem);
}
// assume my library is full of such methods
public int getFirstIndexOf(final BiPredicate<T, T> pIdentifier, final T pItem) {
for (int i = 0; i < mItems.size(); i++) {
final T t = mItems.get(i);
if (pIdentifier.test(t, pItem)) return i;
}
return -1; // not found
}
}
我的“库”类,我想在其中存储模板:BiPredicate<T, T>
package stackoverflow.genericlambdas;
import java.util.Objects;
import java.util.function.BiPredicate;
public class Library {
static public class CLUMSY_IDENTITY_CLASS<T> implements BiPredicate<T, T> {
@Override public boolean test(final T p, final T q) {
return p == q;
}
}
static public class CLUMSY_EQUALITY_CLASS<T> implements BiPredicate<T, T> {
@Override public boolean test(final T p, final T q) {
return Objects.equals(p, q);
}
}
static public final BiPredicate<T, T> IDENTITY = (p, q) -> p == q; // compilation error
static public final BiPredicate<T, T> EQUALITY = (p, q) -> Objects.equals(p, q); // compilation error
}
我的“usage”类,我想在其中使用这些模板:
package stackoverflow.genericlambdas;
import java.util.Objects;
public class GenericLamdasUse {
public static void main(final String[] args) {
final MyListImpl<String> list = new MyListImpl<>();
list.addItem("aa");
list.addItem("bb");
list.addItem("cc");
final String testItem = "cc";
final String testItem2 = "c" + (Math.random() < 2 /* always true */ ? "c" : ""); // this builds a new string that is not == the compile constant String "cc"
final int whatIKnowWorks1 = list.getFirstIndexOf((p, q) -> Objects.equals(p, q), testItem);
final int whatIKnowWorks2 = list.getFirstIndexOf((p, q) -> p == q, testItem);
final int whatIKnowWorks3 = list.getFirstIndexOf(new Library.CLUMSY_IDENTITY_CLASS<>(), testItem); // dont't want the re-instantiation
final int whatIKnowWorks4 = list.getFirstIndexOf(new Library.CLUMSY_EQUALITY_CLASS<>(), testItem); // for ever time i would need that
final Library.CLUMSY_IDENTITY_CLASS<String> clumsy5 = new Library.CLUMSY_IDENTITY_CLASS<>(); // dont't want the re-instantiation
final Library.CLUMSY_EQUALITY_CLASS<String> clumsy6 = new Library.CLUMSY_EQUALITY_CLASS<>();
final int whatIKnowWorks5 = list.getFirstIndexOf(clumsy5, testItem); // for ever time i would need that
final int whatIKnowWorks6 = list.getFirstIndexOf(clumsy6, testItem); // also, the types <String> have to match each time
final int whatIWant1 = list.getFirstIndexOf(Library.EQUALITY, testItem); // I want this, but: compilation error
final int whatIWant2 = list.getFirstIndexOf(Library.IDENTITY, testItem); // I want this, but: compilation error
}
}
答:
如果需要使用类型变量参数化 s,则无法通过静态字段执行此操作,因为必须在作用域中定义类型变量。像这样的东西通常是通过静态方法实现的。BiPredicate
package stackoverflow.genericlambdas;
import java.util.Objects;
import java.util.function.BiPredicate;
public class Library {
public static <T> BiPredicate<T, T> identity() {
return (a, b) -> a == b;
}
public static <T> BiPredicate<T, T> equals()
return Objects::equals;
}
}
如果您不需要类型变量,请参阅 Sweeper 的答案。
IDENTITY
如果应用 PECS,实际上不需要泛型类型参数。EQUALITY
如果你像这样声明它们:
public static final BiPredicate<? super Object, ? super Object> IDENTITY = (p, q) -> p == q;
public static final BiPredicate<? super Object, ? super Object> EQUALITY = Objects::equals;
请注意,您应该在此处使用,因为 的两个类型参数表示它“使用”的类型。super
BiPredicate
然后做同样的事情:getFirstIndexOf
public int getFirstIndexOf(final BiPredicate<? super T, ? super T> pIdentifier, final T pItem) {
现在,您可以简单地传递和到,而不会出现任何错误:IDENTITY
EQUALITY
getFirstIndexOf
list.getFirstIndexOf(IDENTITY, "foo");
当然,如果你无法控制 ,那么你就不能这样做,并且需要声明一个在 Slaw 的答案中返回 like 的方法。getFirstIndex
BiPredicate
public static <T> BiPredicate<T, T> identity() {
return (p, q) -> p == q;
}
请注意,JLS 并不保证在调用此类方法时不会创建新对象,但实际上,它通常经过优化,不会创建新对象。
评论
上一个:对于每个单元格值:重复一系列值
下一个:如何用C语言编写条件实例化#
评论
T
必须在上下文中定义;它不能凭空而来。像这样的东西通常是通过静态方法实现的。例如,.public static <T> BiPredicate<T, T> equality() { return Objects::equals; }
Object::equals
==