Java:过滤与通配符类型可比较的项

huangapple go评论49阅读模式
英文:

Java: Filter items that are comparable to a wildcard type

问题

我正在为一种DSL编写解释器,遇到了一个问题,我想比较两个未知类型的值。我尝试将问题简化为以下形式。

我想定义一个具有以下规范的带有两个参数的函数。

public boolean isMinimumOrThrow(Object minToCheck, Collection<Object> coll);
  1. 如果 minToCheck 不是 Comparable<?> 类型,则我想抛出运行时异常。
  2. 否则,我想过滤掉 coll 中所有可以与 minToCheck 进行比较的对象,然后返回 minToCheck 是否小于或等于 coll 中的每个可比较对象。

第一次尝试

当定义过滤器时,我遇到了困难,即,

public boolean isMinimumOrThrow(Object minToCheck, Collection<Object> coll) {
	if (!(minToCheck instanceof Comparable<?>)) {
		throw new RuntimeException();
	}
	Comparable<?> comparableMin = (Comparable<?>)minToCheck;
	return coll.stream().filter(...).allMatch(item -> comparableMin.compareTo((...)item) <= 0);
}

我不确定能否实现 ...

第二次尝试

为了解决问题,我尝试稍微放松 Comparable 的限制,并定义了自己的接口 MyComparable<T>

public interface MyComparable<T> extends Comparable<T> {
	public Collection<T> filterComparable(Collection<?> values);
}

但即使这样,我仍然遇到了类型错误

The method compareTo(capture#13-of ?) in the type Comparable<capture#13-of ?> is not applicable for the arguments (capture#12-of ?)

与以下代码一起使用

public boolean isMinimumOrThrow(Object minToCheck, Collection<Object> coll) {
	if (!(minToCheck instanceof MyComparable<?>)) {
		throw new RuntimeException();
	}
	MyComparable<?> comparableMin = (MyComparable<?>)minToCheck;
	return comparableMin.filterComparable(coll).stream().allMatch(item -> comparableMin.compareTo(item) <= 0);
}

有什么建议吗?

英文:

I'm writing an interpreter for a DSL and I ran into a problem where I want to compare two values of unknown type. I have tried to reduce the problem to the following.

I want to define a function with two parameters with the following specification.

public boolean isMinimumOrThrow(Object minToCheck, Collection<Object> coll);
  1. If minToCheck is not of type Comparable<?>, then I want to throw a runtime exception.
  2. Otherwise, I want to filter out all objects in coll that I can compare with minToCheck, and then return whether minToCheck is less than or equal to every comparable object in coll.

First attempt

I get in trouble when defining the filter, i.e.,

public boolean isMinimumOrThrow(Object minToCheck, Collection<Object> coll) {
	if (!(minToCheck instanceof Comparable<?>)) {
		throw new RuntimeException();
	}
	Comparable<?> comparableMin = (Comparable<?>)minToCheck;
	return coll.stream().filter(...).allMatch(item -> comparableMin.compareTo((...)item) <= 0);
}

I'm not sure whether it's possible to implement the ....

Second attempt

To work around the problem, I've tried to loosen the restriction of Comparable a bit, and defined my own interface MyComparable<T>

public interface MyComparable<T> extends Comparable<T> {
	public Collection<T> filterComparable(Collection<?> values);
}

but even then, I still get a type error

The method compareTo(capture#13-of ?) in the type Comparable<capture#13-of ?> is not applicable for the arguments (capture#12-of ?)

with the following code

public boolean isMinimumOrThrow(Object minToCheck, Collection<Object> coll) {
	if (!(minToCheck instanceof MyComparable<?>)) {
		throw new RuntimeException();
	}
	MyComparable<?> comparableMin = (MyComparable<?>)minToCheck;
	return comparableMin.filterComparable(coll).stream().allMatch(item -> comparableMin.compareTo(item) <= 0);
}

Any ideas?

答案1

得分: 1

以下是您要翻译的内容:

也许有一个更清晰的解决方案,但您可以坚持您的第一次尝试。可以通过尝试在try-catch中使用compareTo来实现过滤器。这只有在中间步骤中使用原始的Comparable时才能编译。结果将再次是类型安全的(我希望如此),但需要抑制一些中间步骤的警告。所以我的建议是以下内容:

@SuppressWarnings("unchecked")
public static boolean isMinimumOrThrow(Object minToCheck, Collection<Object> coll) {
    if (!(minToCheck instanceof Comparable)) {
        throw new RuntimeException();
    }
    @SuppressWarnings("rawtypes")
    Comparable comparableMin = (Comparable)minToCheck;
    return coll.stream().filter(item -> {
        boolean isComparable = true;
        try {
            comparableMin.compareTo(item);
        } catch (Exception e) {
            isComparable = false;
        }

        return isComparable;
    }).allMatch(item -> comparableMin.compareTo(item) <= 0);
}

public static void main(String[] args) {
    Collection<Object> list = Arrays.asList("bla",5,"blub",2,7);

    System.out.println("Is 0 minimum: " + isMinimumOrThrow(0, list)); // true
    System.out.println("Is 2 minimum: " + isMinimumOrThrow(2, list)); // true
    System.out.println("Is 3 minimum: " + isMinimumOrThrow(3, list)); // false
    System.out.println("Is 'bla' minimum: " + isMinimumOrThrow("bla", list)); // true
    System.out.println("Is 'blub' minimum: " + isMinimumOrThrow("blub", list)); // false
    System.out.println("Is 'some object' minimum: " + isMinimumOrThrow(new Object(), list)); // 抛出RuntimeException

}
英文:

Maybe there is a cleaner solution, but you could stick to your first attempt. The filter can be implemented by simply trying a compareTo in a try-catch. This in turn only compiles if you use raw Comparable in intermediate steps. The result will be typesafe again (I hope), but needs to suppress some warnings for the intermediate steps. So my suggestion is the following:

@SuppressWarnings(&quot;unchecked&quot;)
public static boolean isMinimumOrThrow(Object minToCheck, Collection&lt;Object&gt; coll) {
if (!(minToCheck instanceof Comparable)) {
throw new RuntimeException();
}
@SuppressWarnings(&quot;rawtypes&quot;)
Comparable comparableMin = (Comparable)minToCheck;
return coll.stream().filter(item -&gt; {
boolean isComparable = true;
try {
comparableMin.compareTo(item);
} catch (Exception e) {
isComparable = false;
}
return isComparable;
}).allMatch(item -&gt; comparableMin.compareTo(item) &lt;= 0);
}
public static void main(String[] args) {
Collection&lt;Object&gt; list = Arrays.asList(&quot;bla&quot;,5,&quot;blub&quot;,2,7);
System.out.println(&quot;Is 0 minimum: &quot; + isMinimumOrThrow(0, list)); // true
System.out.println(&quot;Is 2 minimum: &quot; + isMinimumOrThrow(2, list)); // true
System.out.println(&quot;Is 3 minimum: &quot; + isMinimumOrThrow(3, list)); // false
System.out.println(&quot;Is &#39;bla&#39; minimum: &quot; + isMinimumOrThrow(&quot;bla&quot;, list)); // true
System.out.println(&quot;Is &#39;blub&#39; minimum: &quot; + isMinimumOrThrow(&quot;blub&quot;, list)); // false
System.out.println(&quot;Is &#39;some object&#39; minimum: &quot; + isMinimumOrThrow(new Object(), list)); // throws RuntimeException
}

答案2

得分: 0

我对你的代码做了一些小的改动,我相信现在函数已经按照你想要的方式工作了。

首先,我将函数定义为泛型:
&lt;T&gt; boolean isMinimumOrThrow(T minToCheck, Collection&lt;T&gt;)

然后,我简化了一下你的过滤器,并在项目上添加了T的转换:
coll.stream().allMatch(item -&gt; comparableMin.compareTo( (T) item) &lt;= 0);

这里使用了标准的Comparable接口。我认为你的主要问题是“item”上缺少了转换。

一个完整的、适用于整数的工作示例:

import java.util.List;
import java.util.Arrays;
import java.lang.Comparable;
public class Program
{
static &lt;T&gt; boolean isMinimumOrThrow(T minToCheck, Collection&lt;T&gt; coll) {
if (!(minToCheck instanceof Comparable&lt;?&gt;)) {
throw new RuntimeException();
}
Comparable&lt;T&gt; comparableMin = (Comparable&lt;T&gt;) minToCheck;
return coll.stream().allMatch(
item -&gt; comparableMin.compareTo( (T) item) &lt;= 0
);
}
public static void main(String[] args) {
boolean isMinimum = false;
Collection&lt;Integer&gt; list = Arrays.asList(1,2,3,4,5);
isMinimum = isMinimumOrThrow(0, list);
System.out.println(&quot;Is minimum: &quot; + isMinimum);
}
}```
<details>
<summary>英文:</summary>
I did a couple of minor changes to your code and I believe I got the function working as you wanted.
First I defined the function as generic:

<T> boolean isMinimumOrThrow(T minToCheck, Collection<T>)


And I simplified a little bit your filter and added a cast to T on item:

coll.stream().allMatch(item -> comparableMin.compareTo( (T) item) <= 0);


This is using standard Comparable. Your main problem I think was missing the cast on &quot;item&quot;. 
A full working example with integers:

import java.util.Collection;
import java.util.List;
import java.util.Arrays;
import java.lang.Comparable;
public class Program
{
static <T> boolean isMinimumOrThrow(T minToCheck, Collection<T> coll) {
if (!(minToCheck instanceof Comparable<?>)) {
throw new RuntimeException();
}
Comparable<T> comparableMin = (Comparable<T>) minToCheck;
return coll.stream().allMatch(
item -> comparableMin.compareTo( (T) item) <= 0
);
}
public static void main(String[] args) {
boolean isMinimum = false;

    Collection&lt;Integer&gt; list = Arrays.asList(1,2,3,4,5);
isMinimum = isMinimumOrThrow(0, list);
System.out.println(&quot;Is minimum: &quot; + isMinimum);
}

}


</details>

huangapple
  • 本文由 发表于 2023年4月19日 23:53:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76056551.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定