在 java 中使用 while 循环来避免深度嵌套的 if 语句
Use while loop to avoid deeply nested if statements in java
你好,我写了一个像
这样的小函数
public void foo(MyClassA paraA) {
if (paraA == null) return;
MyClassB paraB = doSomeStuff(paraA);
if (paraB == null) return;
MyClassC paraC = doMoreStuff(paraB);
if (paraC == null) return;
....
}
上面的代码很快就失败了,而且很好读(即 return 空值的意图很明确)。但是现在我不想简单地returning,而是想做一些错误记录,所以我改为
public void foo(MyClassA paraA) {
if (paraA == null) {doLog(); return;}
MyClassB paraB = doSomeStuff(paraA);
if (paraB == null) {doLog(); return;}
MyClassC paraC = doMoreStuff(paraB);
if (paraC == null) {doLog(); return;}
....
}
上面的内容也很清晰易读,但我必须重复 doLog() 几次。所以我又改成了
public void foo(MyClassA paraA) {
if (paraA != null) {
MyClassB paraB = doSomeStuff(paraA);
if (paraB != null) {
MyClassC paraC = doMoreStuff(paraB);
if (paraC != null) {
....
return;
}
}
}
doLog();
}
上面只调用了 doLog() 一次,但我以一些嵌套很深的 if 语句结束,这些语句非常丑陋且难以阅读。那么我如何保持像以前一样的清洁度并且只使用一次 doLog() 呢?请注意,不允许为 foo() 使用 return 其他内容而不是 void。而且我还读到使用 try/catch 来反对空检查是一种反模式。
如果我要尝试,我想写这样的东西
public void foo(MyClassA paraA) {
while(true) {
if (paraA == null) break;
MyClassB paraB = doSomeStuff(paraA);
if (paraB == null) break;
MyClassC paraC = doMoreStuff(paraB);
if (paraC == null) break;
....
return;
}
doLog();
}
以上满足了我的所有需求(快速失败,干净,没有嵌套 if),但是这里使用 while 循环是一种反模式,因为这里的 while 循环绝不意味着 运行 更多不止一次?
你觉得这个干净吗
public void foo(MyClassA paraA) {
MyClassB paraB = paraA != null?doSomeStuff(paraA):null;
MyClassC paraC = paraB != null?doMoreStuff(paraB):null;
if (paraC != null) {
....
}
doLog();
}
Java 有一个漂亮的带标签的 break 构造,在这里可能对您有所帮助。
public void foo(MyClassA paraA) {
block: {
if (paraA == null) { break block; }
MyClassB paraB = doSomeStuff(paraA);
if (paraB == null) { break block; }
MyClassC paraC = doMoreStuff(paraB);
if (paraC == null) { break block; }
...
return;
}
doLog();
}
如果你更好地使用多态性,你可以这样做:
public void foo(MyInterface para) {
while (para != null) {
para = para.doStuff();
}
doLog();
}
如果您绝对不能像那样使用多态性,请使用调度程序。
但我以前见过这个,它看起来像一个状态机。给 "java enum state machine" 一个搜索。我感觉这就是你真正想要做的事情。
恕我直言,你的第二个代码片段是你应该做的。
不要试图让您的代码简短。这是一个反模式。
if (a==null) {
log("Failed in step a");
return;
}
B b = a.doSomething();
阅读和理解速度非常快。压缩此代码不会保存任何内容。零。纳达。将其留给 Hotspot VM,并专注于使代码易于理解。 "if null then log return"是经典的,很好理解和接受的模式.
尝试使用这样的 lambda 反模式编写代码 "readable" 已经变得很流行:
B b = ifNullLog(a, () -> a.doSomething())
哪里
T ifNullLog(Object guard, Function<T> func) {
if (guard == null) { doLog(); return null; }
return func.run();
}
但是恕我直言,这完全是一种反模式。事实上,最好的做法是 require 每个 if、else、for、while 的大括号,以便插入这样的日志语句而不会有破坏代码的风险。
像你的第一个代码片段一样的代码:
if (a == null) return;
很危险。 查看苹果 SSL 灾难等各种错误
如果有人在没有注意到缺少的括号的情况下添加了 doLog,该函数将始终 return null。 Apple SSL 错误(或者它是令人心碎的?)本质上是一个
if (a==null)
return;
return;
B b = a.doSomething();
看到这个错误有多微妙了吗?如果它是关于无法访问的代码,你 Java 编译器会幸运地警告你 - 它不一定会警告你否则......通过始终使用括号和格式良好的代码可以很容易地避免这些错误。 格式化代码以避免错误,而不是为了美学。
使用return代码也是可以接受的。只是不要将成功设置为默认值(再次参见 heartbleed)。
Code c = execute(a);
if (c != Code.SUCCESS) {
doLog(c);
return;
}
哪里
Code execute(A a) {
if (a == null) { return Code.FAILED_A_NULL; }
B b = a.doSomething();
if (b == null) { return Code.FAILED_B_NULL; }
...
return Code.SUCCESS;
}
"return"的经典用例,又一个好模式
你好,我写了一个像
这样的小函数public void foo(MyClassA paraA) {
if (paraA == null) return;
MyClassB paraB = doSomeStuff(paraA);
if (paraB == null) return;
MyClassC paraC = doMoreStuff(paraB);
if (paraC == null) return;
....
}
上面的代码很快就失败了,而且很好读(即 return 空值的意图很明确)。但是现在我不想简单地returning,而是想做一些错误记录,所以我改为
public void foo(MyClassA paraA) {
if (paraA == null) {doLog(); return;}
MyClassB paraB = doSomeStuff(paraA);
if (paraB == null) {doLog(); return;}
MyClassC paraC = doMoreStuff(paraB);
if (paraC == null) {doLog(); return;}
....
}
上面的内容也很清晰易读,但我必须重复 doLog() 几次。所以我又改成了
public void foo(MyClassA paraA) {
if (paraA != null) {
MyClassB paraB = doSomeStuff(paraA);
if (paraB != null) {
MyClassC paraC = doMoreStuff(paraB);
if (paraC != null) {
....
return;
}
}
}
doLog();
}
上面只调用了 doLog() 一次,但我以一些嵌套很深的 if 语句结束,这些语句非常丑陋且难以阅读。那么我如何保持像以前一样的清洁度并且只使用一次 doLog() 呢?请注意,不允许为 foo() 使用 return 其他内容而不是 void。而且我还读到使用 try/catch 来反对空检查是一种反模式。
如果我要尝试,我想写这样的东西
public void foo(MyClassA paraA) {
while(true) {
if (paraA == null) break;
MyClassB paraB = doSomeStuff(paraA);
if (paraB == null) break;
MyClassC paraC = doMoreStuff(paraB);
if (paraC == null) break;
....
return;
}
doLog();
}
以上满足了我的所有需求(快速失败,干净,没有嵌套 if),但是这里使用 while 循环是一种反模式,因为这里的 while 循环绝不意味着 运行 更多不止一次?
你觉得这个干净吗
public void foo(MyClassA paraA) {
MyClassB paraB = paraA != null?doSomeStuff(paraA):null;
MyClassC paraC = paraB != null?doMoreStuff(paraB):null;
if (paraC != null) {
....
}
doLog();
}
Java 有一个漂亮的带标签的 break 构造,在这里可能对您有所帮助。
public void foo(MyClassA paraA) {
block: {
if (paraA == null) { break block; }
MyClassB paraB = doSomeStuff(paraA);
if (paraB == null) { break block; }
MyClassC paraC = doMoreStuff(paraB);
if (paraC == null) { break block; }
...
return;
}
doLog();
}
如果你更好地使用多态性,你可以这样做:
public void foo(MyInterface para) {
while (para != null) {
para = para.doStuff();
}
doLog();
}
如果您绝对不能像那样使用多态性,请使用调度程序。
但我以前见过这个,它看起来像一个状态机。给 "java enum state machine" 一个搜索。我感觉这就是你真正想要做的事情。
恕我直言,你的第二个代码片段是你应该做的。
不要试图让您的代码简短。这是一个反模式。
if (a==null) {
log("Failed in step a");
return;
}
B b = a.doSomething();
阅读和理解速度非常快。压缩此代码不会保存任何内容。零。纳达。将其留给 Hotspot VM,并专注于使代码易于理解。 "if null then log return"是经典的,很好理解和接受的模式.
尝试使用这样的 lambda 反模式编写代码 "readable" 已经变得很流行:
B b = ifNullLog(a, () -> a.doSomething())
哪里
T ifNullLog(Object guard, Function<T> func) {
if (guard == null) { doLog(); return null; }
return func.run();
}
但是恕我直言,这完全是一种反模式。事实上,最好的做法是 require 每个 if、else、for、while 的大括号,以便插入这样的日志语句而不会有破坏代码的风险。
像你的第一个代码片段一样的代码:
if (a == null) return;
很危险。 查看苹果 SSL 灾难等各种错误 如果有人在没有注意到缺少的括号的情况下添加了 doLog,该函数将始终 return null。 Apple SSL 错误(或者它是令人心碎的?)本质上是一个
if (a==null)
return;
return;
B b = a.doSomething();
看到这个错误有多微妙了吗?如果它是关于无法访问的代码,你 Java 编译器会幸运地警告你 - 它不一定会警告你否则......通过始终使用括号和格式良好的代码可以很容易地避免这些错误。 格式化代码以避免错误,而不是为了美学。
使用return代码也是可以接受的。只是不要将成功设置为默认值(再次参见 heartbleed)。
Code c = execute(a);
if (c != Code.SUCCESS) {
doLog(c);
return;
}
哪里
Code execute(A a) {
if (a == null) { return Code.FAILED_A_NULL; }
B b = a.doSomething();
if (b == null) { return Code.FAILED_B_NULL; }
...
return Code.SUCCESS;
}
"return"的经典用例,又一个好模式