Java 代码样式:多重返回

Java 代码样式:多重返回,java,return,design-patterns,Java,Return,Design Patterns,我写了一个大致如下的方法: if (hasFoo()) { return calculateFoo(); } else if (hasBar()) { return calculateBar(); } else { return calculateBaz(); } getter非常昂贵,具有…()检查要么会复制大量逻辑,要么就必须重用getter。我可以让has…()方法将get…()的结果存储在一个字段中,并使getter变懒,但是如果has…()没有任何副作用就好了。我可

我写了一个大致如下的方法:

if (hasFoo()) {
   return calculateFoo();
} else if (hasBar()) {
   return calculateBar();
} else {
   return calculateBaz();
}
getter非常昂贵,
具有…()
检查要么会复制大量逻辑,要么就必须重用getter。我可以让
has…()
方法将
get…()
的结果存储在一个字段中,并使getter变懒,但是如果
has…()
没有任何副作用就好了。我可以用嵌套的try{}catch{}块来写这个,但这看起来并不优雅。看来应该有更好的解决办法

编辑:将
get…()
更改为
calculate…()
,以明确它们很昂贵

int result = 0;

if (hasFoo()) {
   result = getFoo();
} else if (hasBar()) {
   result = getBar();
} else {
   result = getBaz();
}

return result;
是我更喜欢使用的习惯用法-使调试时检查变量值更容易


是我更喜欢使用的习惯用法-使调试时检查变量值更容易。

我认为这样做没有错

Object fooBarBaz = null;

if (hasFoo()) {
   foo = getFoo();
} else if (hasBar()) {
   fooBarBaz = getBar();
} else {
   fooBarBaz = getBaz();
}

return fooBarBaz;

我认为这样做没有错

Object fooBarBaz = null;

if (hasFoo()) {
   foo = getFoo();
} else if (hasBar()) {
   fooBarBaz = getBar();
} else {
   fooBarBaz = getBaz();
}

return fooBarBaz;

你可以这样做:

Object bar;
if ((bar = getFoo()) != null) {
  return bar;
} else if ((bar = getBoo()) != null) {
  return bar;
} else {
  return getBaz()
}
这样,您只需要调用get方法,而不需要调用has方法

EDIT
这在可读性更强的格式中也是一样的,它也减少了调用has方法的需要

Object bar = getFoo()

if (bar == null) {
  bar = getBoo()
}

if (bar == null) {
  bar = getBaz()
}

return bar;

你可以这样做:

Object bar;
if ((bar = getFoo()) != null) {
  return bar;
} else if ((bar = getBoo()) != null) {
  return bar;
} else {
  return getBaz()
}
这样,您只需要调用get方法,而不需要调用has方法

EDIT
这在可读性更强的格式中也是一样的,它也减少了调用has方法的需要

Object bar = getFoo()

if (bar == null) {
  bar = getBoo()
}

if (bar == null) {
  bar = getBaz()
}

return bar;

编辑:如果我正确地解释了你的评论,听起来你实际上想要的是:

Result result = calculateFoo();
if (result != null) {
    return result;
}
result = calculateBar();
if (result != null) {
    return result;
}
return calculateBaz();
bool checked_xxx = false;
double xxx_state;

bool hasXXX() {
   // do expensive stuff
   ...

   // save temporary state variables
   xxx_state = ... 

   // remember that we've been here
   checked_xxx = true;

   // send back the required value
   return has_xxx;
}

double calculateXXX() {
    // make sure that hasXXX was called, and is valid
    if (!checked_xxx && !hasXXX()) {
        // should never happen - you called calculateXXX when hasXXX() == false
        throw new RuntimeException("precondition failed");
    }

    // use the previously calculated temporary state variables
    ...

    // send back the final result
    return xxx;
}
。。。其中,如果相应的
has
方法返回false,则每个
calculate
方法返回
null
。现在,如果
null
是一个有效的“实”返回值,您可以始终包装结果,以便
calculatefo
返回一个基本上可以说“是的,我有一个有效值,它是X”或“否,我没有一个有效值”(一个“可能”类型)


原始答案

我会让你的代码保持原样。我认为使用多个返回语句是没有问题的,因为这是最清晰的方法——在本例中,我相信是这样的

您要明确的是,一旦到达每个“叶”部分,您就确切地知道返回值是什么,并且在离开方法之前应该执行的唯一其他代码是
finally
块中的任何清理代码

在没有try/finally或GC(您确实希望确保在一个地方完成所有清理)的语言中,有一个单一的退出点是有意义的,但在Java中,我认为当您知道结果时返回比使用单独的局部变量更清楚地说明您的意图

已经说过,另一个可供选择的方案是使用条件运算符,设置代码,这样它显然经过一系列测试并在找到第一个“匹配”时返回:


缺点是这种模式在你第一次看到它时看起来有点奇怪,但一旦你习惯了它,我发现它是一种非常简洁的编码这种逻辑的方法。

编辑:如果我正确地解释了你的评论,听起来你真的想要这样的东西:

Result result = calculateFoo();
if (result != null) {
    return result;
}
result = calculateBar();
if (result != null) {
    return result;
}
return calculateBaz();
bool checked_xxx = false;
double xxx_state;

bool hasXXX() {
   // do expensive stuff
   ...

   // save temporary state variables
   xxx_state = ... 

   // remember that we've been here
   checked_xxx = true;

   // send back the required value
   return has_xxx;
}

double calculateXXX() {
    // make sure that hasXXX was called, and is valid
    if (!checked_xxx && !hasXXX()) {
        // should never happen - you called calculateXXX when hasXXX() == false
        throw new RuntimeException("precondition failed");
    }

    // use the previously calculated temporary state variables
    ...

    // send back the final result
    return xxx;
}
。。。其中,如果相应的
has
方法返回false,则每个
calculate
方法返回
null
。现在,如果
null
是一个有效的“实”返回值,您可以始终包装结果,以便
calculatefo
返回一个基本上可以说“是的,我有一个有效值,它是X”或“否,我没有一个有效值”(一个“可能”类型)


原始答案

我会让你的代码保持原样。我认为使用多个返回语句是没有问题的,因为这是最清晰的方法——在本例中,我相信是这样的

您要明确的是,一旦到达每个“叶”部分,您就确切地知道返回值是什么,并且在离开方法之前应该执行的唯一其他代码是
finally
块中的任何清理代码

在没有try/finally或GC(您确实希望确保在一个地方完成所有清理)的语言中,有一个单一的退出点是有意义的,但在Java中,我认为当您知道结果时返回比使用单独的局部变量更清楚地说明您的意图

已经说过,另一个可供选择的方案是使用条件运算符,设置代码,这样它显然经过一系列测试并在找到第一个“匹配”时返回:

缺点是,这种模式在你第一次看到它时看起来有点奇怪,但一旦你习惯了,我发现它是一种非常简洁的编码这种逻辑的方式。

我更喜欢这种方式:

if (hasFoo()) {
    return calculateFoo();
}

if (hasBar()) {
    return calculateBar();
}

return calculateBaz();
这都是品味和习俗的问题。

我更喜欢这样:

if (hasFoo()) {
    return calculateFoo();
}

if (hasBar()) {
    return calculateBar();
}

return calculateBaz();

这都是一个品味和惯例的问题。

我不确定这是否是您的情况,但我会尝试完全重构代码。目前,据我所知,您的代码如下所示(示例):

基本上,这里发生的事情是,使用相同的代码检查是否可以返回Foo,以及构造Foo本身。我会将其重构为:

/**
* @returns instance of Foo or null if Foo is not found
*/
Foo getFoo() {
    DataObject do = getSomeDataSource().getSomeDataObject();
    F f = do.getF();
    if (f == null) {
        return null; //Foo can not be created
    }
    O o = do.getO();
    if (o == null) {
        return null; //Foo can not be created
    }

    return new Foo(f,o);
}
现在,您的原始代码将类似于此:

Result r;

r = getFoo();
if (r == null) {
    r = getBoo();
}
if (r == null) {
    r = getDoo();
}
return r;

我不确定这是否是您的情况,但我会尝试完全重构代码。目前,据我所知,您的代码如下所示(示例):

基本上,这里发生的事情是,使用相同的代码检查是否可以返回Foo,以及构造Foo本身。我会将其重构为:

/**
* @returns instance of Foo or null if Foo is not found
*/
Foo getFoo() {
    DataObject do = getSomeDataSource().getSomeDataObject();
    F f = do.getF();
    if (f == null) {
        return null; //Foo can not be created
    }
    O o = do.getO();
    if (o == null) {
        return null; //Foo can not be created
    }

    return new Foo(f,o);
}
现在,您的原始代码将类似于此:

Result r;

r = getFoo();
if (r == null) {
    r = getBoo();
}
if (r == null) {
    r = getDoo();
}
return r;
这不是一个“是否可以做多次回报”的问题-你的多次回报是好的

这是一个重构和/或状态存储问题

如果您有:

bool hasXXX() {
    // do lots of stuff
    ...

    return has_xxx;
}

那么问题的复杂性取决于
hasXXX()
计算产品是否