我目前正在处理XML文件,我正在寻找一种更好的方法来避免尝试/捕获块。
这是事情。假设我有一个XML文件。
<A>
<BB>37</BB>
<CC>
<DDD>1</DDD>
</CC>
</A>
事实上,我把它变成了一个对象,这意味着我可以做到 myXml.getA()等等。
在我的代码中,我搜索了这个对象中的给定元素,这意味着我有很多行,比如
int ddd = myXml.getA().getCC().getDDD();
问题是某些元素可能不存在,例如,另一个XML元素可能只是这样:
<A'>
<BB'>37</BB'>
</A'>
因此,如果我尝试获取ddd, getCC()会引发 NullPointerException 。
最后,我最终将其编码为:
int ddd;
try{
ddd = myXml.getA().getCC().getDDD();
}
catch (NullPointerException e){
ddd = 0;
}
这可行,但代码变得非常难看。 我正在寻找类似
的解决方案int ddd = setInt(myXml.getA().getCC().getDDD(), 0);
如果方法引发异常,0 是默认值。
有一个很好的方法吗?
到目前为止,我找不到不会引发错误的解决方案。
谢谢你的帮助!
编辑:只是为了得到与XML相关的答案。 我向每个人展示了xml部分以了解问题。 在我的代码中,我无法访问XML,只能访问代表它的对象。
为了简短起见,我真正喜欢的是某种用于测试吸气剂的isNull方法。
答案 0 :(得分:2)
您可以查看Null objec pattern。
例如:
public class A {
private C c;
public C getC() {
if (c == null) {
c = new C(0); // the "null object"
}
return c;
}
}
public class C {
private int d;
public C(int d) {
this.d = d;
}
public int getD() {
return d;
}
}
但是个人,我对这段代码感觉不好:
int ddd = myXml.getA().getCC().getDDD();
强烈违反了law of Demeter。类调用者对A,C和D知之甚多。这段代码显然很难适应和维护。
答案 1 :(得分:2)
这有点像使用jaxb一样烦恼。在我的公司,我们做了足够的jaxb工作,值得编写一个xjc插件,它生成每个getter的“安全”版本,保证为任何非平凡的值返回非null值(在一个非常重要的值的情况下是不可变的实例)子对象并不存在)。
以下是我们生成的模型实体的示例:
public class ExampleUser implements Serializable {
private final static long serialVersionUID = 20090127L;
@XmlAttribute
protected String name;
@XmlAttribute
protected String email;
public final static ExampleUser EMPTY_INSTANCE = new ExampleUser() {
private static final long serialVersionUID = 0L;
@Override
public void setName(java.lang.String value) { throw new UnsupportedOperationException(); }
@Override
public void setEmail(java.lang.String value) { throw new UnsupportedOperationException(); }
};
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public String getEmail() {
return email;
}
public void setEmail(String value) {
this.email = value;
}
}
public class ExampleAccount implements Serializable {
private final static long serialVersionUID = 20090127L;
protected ExampleUser user;
@XmlElement(name = "alias")
protected List<String> aliases;
@XmlAttribute
protected String id;
@XmlAttribute
protected String name;
public final static ExampleAccount EMPTY_INSTANCE = new ExampleAccount() {
private static final long serialVersionUID = 0L;
@Override
public void setUser(com.boomi.platform.api.ExampleUser value) { throw new UnsupportedOperationException(); }
@Override
public List<String> getAliases() { return java.util.Collections.emptyList(); }
@Override
public void setId(java.lang.String value) { throw new UnsupportedOperationException(); }
@Override
public void setName(java.lang.String value) { throw new UnsupportedOperationException(); }
};
public ExampleUser getUser() {
return user;
}
public void setUser(ExampleUser value) {
this.user = value;
}
public List<String> getAliases() {
if (aliases == null) {
aliases = new ArrayList<String>();
}
return this.aliases;
}
public String getId() {
return id;
}
public void setId(String value) {
this.id = value;
}
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public ExampleUser safeGetUser() {
return (getUser() != null) ? getUser() : ExampleUser.EMPTY_INSTANCE;
}
}
所以你可以编写这段代码而不用担心NPE:
userEmail = account.safeGetUser().getEmail();
答案 2 :(得分:1)
解决此类问题的两种常用方法是其他答案已经涵盖的空对象模式,并键入安全空值,例如Scala的选项。
http://www.scala-lang.org/api/current/scala/Option.html
有一些Java版本的Option敲响了。
http://functionaljava.googlecode.com/svn/artifacts/2.20/javadoc/fj/data/Option.html
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Optional.html
与flatmap结合使用时,类型安全空值特别有用。
答案 3 :(得分:1)
使用Apache common-beanutils创建您的set方法。它将使用反射,然后你只有一个地方来捕捉错误。
它看起来像这样(没有编码,所以借口语法错误)。
int getInt(Object root, String beanPattern, int defaultValue)
{
try
{
return PropertyUtils.getNestedProperty(root, beanPattern);
}
catch (Exception e)
{
return 0;
}
}
这将被称为。
int ddd = getInt(myXml, "A.CC.DDD", 0);
答案 4 :(得分:0)
你不能只编写一个通用的函数来为每个值调用,并返回值或0。
像
这样的东西myGetSomething(FOO){
try {getFOO} catch ...
}
然后您的代码本身看起来不错,但该函数基本上每次调用都有一个try-catch。
答案 5 :(得分:0)
使用Xpath query代替get方法。如果它找不到元素路径,它将为您提供一个空列表。
List ddds = myXml.query("/AA/BB/CC/DDD");
if (!ddds.empty()) {}
正确的语法取决于您使用的XML库。
答案 6 :(得分:0)