Iterating over java List that involves Java generics <?> in Scala
I have an API (from third party java library) that looks like:
public List<?> getByXPath(String xpathExpr)
defined on a class called DomNode
I try this in scala:
node.getByXPath(xpath).toList.foreach {node: DomElement =>
node.insertBefore(otherNode)
}
But I get compile error on node.getByXPath. error: "type mismatch; found : (com.html.DomElement) => Unit required: (?0) => ? where type ?0"
If I change it into:
node.getByXPath(xpath).toList.foreach {node =>
开发者_如何学JAVA
node.insertBefore(otherNode)
}
then the error goes away but then I get error on node.insertBefore(otherNode) error: "value insertBefore is not a member of ?0"
What is the answer to this problem?
Do this:
node.getByXPath(xpath).toList.foreach {
case node: DomElement => node.insertBefore(otherNode)
}
By using case
, you turn it into a pattern matching function. If there's any non-DomElement returned, you'll get an exception -- you can add another case
match for the default case to handle it, if necessary.
What you shouldn't do is use asInstanceOf
. That throws away any type safety for little to no gain.
You'll have to cast it. ie,
node.getByXPath(xpath).toList.foreach {node =>
node.asInstanceOf[DomElement].insertBefore(otherNode)
}
You would have the same issue in Java as the type of List elements is unknown.
(I am assuming every element actually is a DomElement)
EDIT:
Daniel is right, there is a better way to do this. For example, you can throw a much nicer exception (as compared to ClassCastException or MatchError). Eg.
node.getByXPath(xpath).toList.foreach {
case node: DomElement => node.insertBefore(otherNode)
case _: => throw new Exception("Expecting a DomElement, got a " + node.getClass.getName)
}
精彩评论