我们可以用 Java 中的泛型做什么来让它们看起来更好:
我有这种方法可以使用列表元素的属性之一将 List
转换为 Map
:
简而言之,它看起来像这样:
private Map<String, List<Diagnostic<? extends JavaFileObject>>> toMap( List<Diagnostic<? extends JavaFileObject>> diagnostics ) {
Map<String, List<Diagnostic<? extends JavaFileObject>>> result = new HashMap<String, List<Diagnostic<? extends JavaFileObject>>>();
for ( Diagnostic<? extends JavaFileObject> d : diagnostics ) {
List<Diagnostic<? extends JavaFileObject>> list = null;
if ( !result.containsKey( d.getCode() ) ) {
list = new ArrayList<Diagnostic<? extends JavaFileObject>>();
result.put( d.getCode(), list );
} else {
list = result.get( d.getCode() );
}
assert list != null;
list.add( d );
}
return result;
}
Yiack!..
我喜欢泛型很多,我在它们之前使用 java 并且我不想回到铸造一切时代,但是当泛型包含它本身作为元素的泛型元素时,事情就会变得混乱。
我知道在Java1.7中我们将能够使用“diamond”运算符,但应该还有另一种方法。
这就是非通用版本中的样子:
private Map toMap( List diagnostics ) {
Map result = new HashMap();
for( Object o : diagnostics ) {
Diagnostic d = ( Diagnostic ) o;
List list = null;
if( !result.containsKey( d.getCode() ) ) {
list = new ArrayList();
result.put( d.getCode() , list );
} else {
list = result.get( d.getCode() );
}
assert list != null;
list.add( d );
}
return result;
}
大约,我没有尝试编译它。
其他语言如何处理这个问题?例如 C#?,Scala?我非常喜欢 SML 或 Haskell 的处理方式,但我认为太多的魔法可能会造成伤害(但这当然是主观的)
有解决方法吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
在 Scala 中,这看起来像:
它没有经过测试,因为我无法访问
Diagnostic
的代码UPDATE
这将教我在深夜发帖,它是实际上要容易得多...
给定任何
Diagnostic
对象序列:它们可以轻松地用一个方法进行分组:
但它比这更复杂一点!
一个更大的问题是
Diagnostic
是 Java 标准库的一部分,因此您无法使用方差注释重写它(在代码后面会详细介绍)。不过,包装器可以解决这个问题,幸运的是它不太大:[S+]
中的+
将此类标记为协变,因此RichDiagnostic[A]如果
被视为A
是B
的子类,则RichDiagnostic[B]
的子类。这是避免令人讨厌的通用签名的关键,不再有或
!
它也很容易使用:
如果诊断最初作为 Java 列表提供,那么像
map
这样的方法将不会自动可供您使用,但转换是微不足道的:构建此集合只需一个 -射击操作,并且如果将条目添加到基础列表中则必须重复,但我怀疑这不会成为问题。
In Scala, this would look something like:
It's not tested, as I have no access to the code for
Diagnostic
UPDATE
This'll teach me to post late at night, it's actually far easier...
Given any sequence of
Diagnostic
objects:they can easily be grouped with a single method:
But it's a little bit more complicated than that!
A bigger problem is that
Diagnostic
is part of the Java standard library, so you're not able to rewrite it with variance annotations (more on that after the code). A wrapper would do the trick though, and fortunately it's not too big:The
+
in[S+]
marks this class as covariant, so aRichDiagnostic[A]
is considered to be a subclass ofRichDiagnostic[B]
ifA
is a subclass ofB
. This is the key to avoiding nasty generic signatures, no more<? extends T>
or<? super T>
!It's easy enough to use, too:
If the Diagnostics are originally supplied as a Java List then methods like
map
won't automatically be available to you, but conversion is trivial:Building this collection is a one-shot operation, and will have to be repeated if entries are added to the underlying list, but I suspect that won't be a problem.
很好的例子。在通用版本中,有 19 个类型参数;在原始版本中,只有 1 个演员。由于这只是一个私有方法,因此我会使用原始版本。即使它更加公开,它仍然可以保留原始方法主体,但具有完整的通用签名。可能就像
在签名和 Java 7 中更通用的类型一样,我们可以有
8 个类型参数。
Great example. In the generic version, there are 19 type arguments; in the raw version, there is only 1 cast. Since this is just a private method, I'd go with the raw version. Even if it's more public, it can still keep the raw method body, but with full generic signature. Probably something like
With more general typing in signature, and Java 7, we can have
8 type arguments.
就我个人而言,我会尝试打破这样的东西(Eclipse编译 - 没有尝试运行)
Personally I would try breaking something like this (Eclipse compiled - not tried running)
我认为这里的一些评论已经得出了“答案”,但我认为到目前为止还没有人给出规范的表述。
类型参数的引入极大地简化了方法的内部结构,同时保持了签名的表达能力。
应该指出的是,这是与所提出的问题不同的方法,但总的来说可能更正确。不同之处在于此处给出的方法将确保诊断的参数化类型对于该方法的输入和输出都是相同的。
不幸的是,在这种情况下,两个构造函数的调用阻止了我们进一步使用类型参数(特别是 Map),尽管如果我们愿意允许自己进行强制转换,我们可以使该方法更加简洁。
I think the 'answer' has been arrived at by some of the comments here but I don't think anyone so far has given the canonical formulation.
The introduction of the type parameter greatly simplifies the internals of the method, while keeping the expressiveness of the signature.
It should be noted that this is a different method to the question as posed, but on balance is probably more correct. The difference being the method given here will ensure that the parameterised type of the Diagnostic is the same for both the input and output of the method.
Unfortunately in this case the invocation of the two constructors prevents us making further use of type parameters (in particular for the Map), though if we were willing to permit ourselves a cast we could make the method even more terse.
首先,你的方法是不是错了?...我的意思是,它不应该更像
另外,你总是可以使用静态实用方法来模拟菱形运算符,这些方法可以为你提供某种类型推断。也就是说
,你的方法看起来会像
至少实例化会更小......
请注意,如果您使用 google guava 库,您可能已经拥有此实用方法。
如果你将它与 Curtain Dog 给你的答案结合起来,你会得到
First, isn't your method wrong?...I mean, shouldn't it be more like
Also, you can always emulate the diamond operator with static utility methods that give you some sort of type inference. That is to say
and then your method will look like
At least instantiations will be smaller....
Note that you may already have this utility methods if you are using google guava library.
And if you combine it with the answer Curtain Dog gave you, you get
综合大家在这里的建议,这就是我所做的:
我创建了一个新类
DiagnosticList
来包装ArrayList>
这非常简单:
然后我可以更改方法签名。
这是有很多可读性的。
虽然我可能会改变原始的程序语义,但我认为我会在可维护性方面受益。
Mashing up everyone's here suggestions, this is what I did:
I created a new class
DiagnosticList
to wrap theArrayList<Diagnostic<? extends JavaFileObject>>
It is dead simple:
And then I could cange the method signature.
Which is way lot readable.
While I might change the original program semantics, I think I will benefit in maintainability.
您定义一个名为
T
的类型参数。然后,您可以在泛型中使用T
,如下所示:在上面,您将看到定义为
的类型参数,并且您可以在任何需要的地方重用 T。这会让它变得更干净一点。You define one type parameter named
T
. Then you can useT
within your generic like this:Above you will see the type parameter defined as
<T extends JavaFileObject>
and you reuse T everywhere you need to. This will make it a bit cleaner.