1

我目前正在使用 XML 文件,并且正在寻找一种更好的方法来避免 try/catch 块。

事情就是这样。假设我有一个 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 方法来测试我的吸气剂。

4

7 回答 7

2

您可以查看Null 对象模式

例如 :

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();

这是对得墨忒耳法则的强烈违反。类调用者对 A、C 和 D 的了解太多。这段代码显然难以适应和维护。

于 2012-09-07T13:48:57.087 回答
2

这是与 jaxb 一起工作的一种烦恼。在我的公司,我们使用 jaxb 做了足够多的工作,值得编写一个 xjc 插件,它生成每个 getter 的“安全”版本,保证为任何非平凡值返回非空值(不可变实例在子对象实际上并不存在)。

这是我们生成的模型实体的示例:

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();
于 2012-09-07T13:54:32.300 回答
1

解决此类问题的两种一般方法是其他答案已经涵盖的空对象模式,以及类型安全的空值,例如 Scala 的 Option。

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

与平面图结合使用时,类型安全的空值特别有用。

于 2012-09-07T14:01:59.117 回答
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);
于 2012-09-07T14:20:33.233 回答
0

使用Xpath 查询而不是 get 方法。如果找不到元素路径,它会给你一个空列表。

List ddds = myXml.query("/AA/BB/CC/DDD");
if (!ddds.empty()) {}

正确的语法取决于您使用的 XML 库。

于 2012-09-07T13:37:39.343 回答
0

你不能只写一个足够通用的函数来为每个值调用,并返回值或 0。

就像是

myGetSomething(FOO){
  try {getFOO} catch ...
}

然后您的代码本身看起来不错,但该函数基本上对每个调用都有一个 try-catch。

于 2012-09-07T13:32:42.210 回答
0

用GroovyXtend编写部分代码;两者都支持表达式左侧的?.返回计算结果为的语法。他们也摆脱了无用的,所以你可以写:nullnullget

myXml.a?.cc?.ddd

与 Groovy 相比,Xtend 的语法更差,但它编译为纯 Java,因此您只需在代码中添加一个带有一些帮助程序类的 JAR 即可使用结果。

于 2012-09-07T14:12:57.847 回答