重构一个调用其他抛出异常的方法的方法

时间:2009-09-15 14:23:18

标签: java refactoring

我有几个(超过20个)方法(getXXX())可能会在调用它们时引发异常(NotCalculatedException)。

在另一种方法中,我需要访问这些方法给出的结果。目前,我有一个可怕的代码,看起来像:

public void myMethod() {
    StringBuffer sb = new StringBuffer();
    // Get 'foo' result...
    sb.append("foo = ");
    try {
        sb.append(getFoo());
    } catch (NotCalculatedException nce) {
        sb.append("not calculated.");
    }
    // Get 'bar' result...
    sb.append("\nbar = ");
    try {
        sb.append(getBar());
    } catch (NotCalculatedException nce) {
        sb.append("not calculated.");
    }
    ...
}

不修改getXXX方法(因此他们必须保留throws NotCalculatedException),您如何重构/简化myMethod()以使其看起来更好?< / p>

请注意,此项目仍在使用Java 1.4 :(


修改

无法将所有getXXX()方法放在try { ... }块中,因为如果一个方法抛出NotCalculatedException,StringBuffer将不完整。

public void myMethod() {
    StringBuffer sb = new StringBuffer();
    try {
        sb.append("foo = ");
        sb.append(getFoo());
        sb.append("\nbar = ");
        sb.append(getBar());
    } catch (NotCalculatedException nce) {
        sb.append("not calculated.");
    }
    ...
}

换句话说,如果getFoo()抛出NotCalculatedException,我希望有这种输出:

foo = not calculated
bar = xxx
...

如果我把所有内容放在一个try { ... }中,我会得到那个我不想得到的输出:

foo = not calculated

7 个答案:

答案 0 :(得分:2)

我认为你不应该使用NotCalculatedException来控制逻辑。

但我对此有一些了解。

  1. 您需要另一个getter方法

    sb.append(this.getFoo(“not calculated”));

  2. 创建hasValue方法

    sb.append(hasFoo()?this.getFoo():“not calculated”);

  3. 创建一个通用的getter方法

    sb.append(this.getValueByName( “富”));

答案 1 :(得分:1)

对于每个getXXX,您可以添加包裹异常的getXXXOrDefault(),并返回getXXX或“未计算”的值。

public void myMethod() {    
        StringBuffer sb = new StringBuffer();    
        // Get 'foo' result...    
        sb.append("foo = ");
        sb.append(getFooOrDefault());
        // Get 'bar' result...    
        sb.append("\nbar = ");
        sb.append(getBarOrDefault());
        // ...
}

public Object getFooOrDefault() {
        try {
                return getFoo();
        } catch() {
                return "not calculated.";
        }
}

或者......使用反思

public Object getValueOrDefault(String methodName) {
        try {
                // 1 . Find methodName
                // 2 . Invoke methodName 
        } catch() {
                return "not calculated.";
        }
}

但我认为我仍然更喜欢第一种选择。

答案 2 :(得分:1)

我的建议是更多代码,但改进了myMethod的可读性:

public void myMethod() {
    StringBuilder resultBilder = new StringBuilder();

    resultBuilder.append("foo=");
    appendFooResult(resultBuilder);
    resultBuilder.append("\nbar=");
    appendBarResult(resultBuilder);

    ...
}

private void appendFooResult(StringBuilder builder) {
    String fooResult = null;
    try {
        fooResult = getFoo();
    } catch (NotCalculatedException nce) {
        fooResult = "not calculated.";
    }
    builder.append(fooResult);
}

private void appendBarResult(StringBuilder builder) {
    String barResult = null;
    try {
        barResult = getBar();
    } catch (NotCalculatedException nce) {
        barResult = "not calculated.";
    }
    builder.append(barResult);
}

答案 3 :(得分:1)

我认为你应该保留你的代码。它很冗长,但很容易分辨出它的作用,而且行为正确。

答案 4 :(得分:0)

您可以在数组中存储“foo”,“bar”等。围绕这些循环,打印出每个,然后使用反射来查找/调用相应的getFoo(),getBar()。不好,我承认。

有关详细信息,请参阅Method对象。

编辑:或者,利用AspectJ围绕该对象的每个getXXX()方法调用并捕获异常。

答案 5 :(得分:0)

你可以使用Execute Around成语。不幸的是,Java语法很冗长,所以在简单的情况下它并不是一个好的结果。假设NotCalculatedException是一个unchekd异常。

appendThing(sb, "foo = ", new GetValue() { public Object get() {
     return getFoo();
}});
appendThing(sb, "bar = ", new GetValue() { public Object get() {
     return getBar();
}});

另一个丑陋的方法是结合循环和开关:

int property = 0;
lp: for (;;) {
    String name = null; // Ugh.
    try { 
        final Object value;
        switch (property) {
            case 0: name= "foo"; value = getFoo(); break;
            case 1: name= "bar"; value = getBar(); break;
            default: break lp;
        }
        ++property;
        sb.append(name).append(" = ").append(value).append('\n');
    } catch (NotCalculatedException exc) {
        sb.append(name).append(" = ").append("not calculated.\n");
    }
}

或者,为每个参数设置枚举和开关。只是不要使用反射!

答案 6 :(得分:0)

似乎Java没有C#开箱即用的代表 - 但谷歌向我展示了ways to roll your own。所以以下内容可能会尝试......

public static PrintProperty(JavaDelegateWithAName del, StringBuilder collector)
{
  try
  {
    collector.append( del.Name+ " = " );
    collector.append( del.Target.Invoke() );
  }
  catch(NotCalculatedException nce) 
  { collector.append("NotCalculated"); }
}

...主要

foreach(JavaDelegateWithAName entry in collectionOfNamedJavaDelegates)
  SomeUtilityClass.PrintProperty(entry, sb);