[ Java ] 方法里有很多判断需要提前结束,很多重复代码,求大神! - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
nicepink
V2EX    程序员

[ Java ] 方法里有很多判断需要提前结束,很多重复代码,求大神!

  nicepink 2021-10-21 13:56:21 +08:00 3808 次点击
这是一个创建于 1451 天前的主题,其中的信息可能已经有所发展或是发生改变。

因为几个查询条件耗时久查到结果就提前结束,但是有重复的地方觉得不够优雅 if 判断那一块

 private void prepareBookingOffice(BrChangedEvent brChangedEvent) { BrGeneralInfoDto brGeneralInfoDto = Optional.ofNullable(brChangedEvent) .map(BrChangedEvent::getBrDto) .map(BrDto::getGeneralInfo) .orElse(BrGeneralInfoDto.builder().build()); if (StringUtils.isNotEmpty(brGeneralInfoDto.getBookingOfficeCode())) { return; } // 耗时 String officeCode = getOfficeCodeByOfficeUnlLocCode(brGeneralInfoDto); // 重复 if (StringUtils.isNotEmpty(officeCode)) { brGeneralInfoDto.setBookingOfficeCode(officeCode); return; } // 耗时 officeCode = getOfficeCodeByPor(brChangedEvent); // 重复 if (StringUtils.isNotEmpty(officeCode)) { brGeneralInfoDto.setBookingOfficeCode(officeCode); return; } // 耗时 officeCode = getOfficeCodeByFnd(brChangedEvent); // 重复 if (StringUtils.isNotEmpty(officeCode)) { brGeneralInfoDto.setBookingOfficeCode(officeCode); return; } // 耗时 officeCode = getOfficeCodeByPol(brChangedEvent); // 重复 if (StringUtils.isNotEmpty(officeCode)) { brGeneralInfoDto.setBookingOfficeCode(officeCode); } } 
第 1 条附言    2021-10-21 15:57:35 +08:00

有些回复有些不太理解(知识储备不够...),后续再研究研究

目前先尝试了这位老哥的写法:

public class OptionalChain<T> { private T value; private OptionalChain(T val) { value = val; } public static <T> OptionalChain<T> of(Supplier<T> supplier) { return new OptionalChain<>(supplier.get()); } public OptionalChain<T> or(Supplier<T> supplier) { if (StringUtils.isEmpty(value)) { value = supplier.get(); } return this; } public T get() { return value; } } private void prepareBookingOffice(BrChangedEvent brChangedEvent) { BrGeneralInfoDto brGeneralInfoDto = Optional.ofNullable(brChangedEvent) .map(BrChangedEvent::getBrDto) .map(BrDto::getGeneralInfo) .orElse(BrGeneralInfoDto.builder().build()); brGeneralInfoDto.setBookingOfficeCode(OptionalChain.of(() -> brGeneralInfoDto.getBookingOfficeCode()) .or(() -> getOfficeCodeByOfficeUnlLocCode(brGeneralInfoDto)) .or(() -> getOfficeCodeByPor(brChangedEvent)) .or(() -> getOfficeCodeByFnd(brChangedEvent)) .or(() -> getOfficeCodeByPol(brChangedEvent)) .or(() -> StringUtils.EMPTY) .get()); } 

补充一下:

  • 这个问题起因是因为昨天 code review 的时候同事觉得我这里可以改进,但是没有思路
  • 这里耗时的地方其实也就是 call 其他服务去拿数据,顺序要固定,是业务上的要求
  • 有些老哥说觉得没必要改,其实我也在想有没有必要,主要是想让代码既清楚又不冗余
23 条回复    2021-10-21 23:04:15 +08:00
itning
    1
itning  
   2021-10-21 13:59:57 +08:00
封装 继承 多态
aguesuka
    2
aguesuka  
   2021-10-21 14:03:37 +08:00
把耗时函数改成 lambda 保存到 List 中
zoharSoul
    3
zoharSoul  
   2021-10-21 14:07:07 +08:00
没什么问题 挺好看懂的
zsl199512101234
    4
zsl199512101234  
   2021-10-21 14:11:03 +08:00   1
二楼的方法,把耗时函数改成 lambda 保存到 list 中去,然后循环调用直到不为空就赋值并且 break
zjsxwc
    5
zjsxwc  
   2021-10-21 14:12:18 +08:00
for 循环遍历 List
chendy
    6
chendy  
   2021-10-21 14:12:33 +08:00
第一步,把“取 officeCode”抽出去,如果方法不是很多而且也不怎么调整,做到这里就可以了

private String getOfficeCode(BrChangedEvent e){
String code = findOfficeCodeByA(e);
if (!StringUtil.isEmpty(code)) {
return code;
}
// 后面的差不多
}

如果方法比较多且需要调整,那么就进一步抽

private List<Function<BrChangedEvent, String>> codeFinders;

{
codeFinders.add(this::findOfficeCodeByA);
codeFinders.add(this::findOfficeCodeByB);
codeFinders.add(this::findOfficeCodeByC);
}


private String getOfficeCode(BrChangedEvent e) {
for(Function<BrChangedEvent, String>> finder : codeFinders) {
String code = finder.apply(codeFinders);
if(!StringUtil.isEmpty(code)){
return code;
}
return null;
}
}
admol
    7
admol  
   2021-10-21 14:12:42 +08:00
如果你只是觉得 if 有点多,给你提供一个思路,你看是否可行

public static void main(String[] args){
String officeCode = null;
if(Objects.nonNull(officeCode = a()) || Objects.nonNull(officeCode = b())|| Objects.nonNull(officeCode = c())){
}else{
officeCode = "default value";
}
System.out.println("officeCode:"+officeCode);
}

private static String c(){
System.out.println("C");
return "C";
}
private static String b(){
System.out.println("B");
return "B";
}

private static String a(){
System.out.println("A");
return null;
}
zsl199512101234
    8
zsl199512101234  
   2021-10-21 14:14:31 +08:00
```java
@FunctionalInterface
public interface OfficeCodeService {
BookingOfficeCode getOfficeCode(BrGeneralInfoDto brGeneralInfoDto);
}
```
mango88
    9
mango88  
   2021-10-21 14:15:15 +08:00
耗时操作有优先级要求吗 ?

还是只要任一返回值就可以了 ? 如果是任一个操作返回就满足需求,可以试试用 CompletableFuture.anyOf()
uCharles
    10
uCharles  
   2021-10-21 14:15:48 +08:00
试试抽取之后用 Optional 来进行判断
mango88
    11
mango88  
   2021-10-21 14:18:17 +08:00
@mango88 每一步耗时操作可能会有空值返回 这样就不行了。

理解错了,6L 的方案会好点。
ipwx
    12
ipwx  
   2021-10-21 14:18:21 +08:00
不懂 Java,伪代码

interface IAction { String run(); }

class GetOfficeCodeByOfficeUnlLocCodeAction implements IAction { ... };
class GetOfficeCodeByPorAction implements IAction { ... };

。。。


List<IAction> actiOns= {
new GetOfficeCodeByOfficeUnlLocCodeAction(...),
new GetOfficeCodeByPorAction(...)
};

for (action in actions) {
String officeCode = getOfficeCodeByOfficeUnlLocCode(brGeneralInfoDto);
// 重复
if (StringUtils.isNotEmpty(officeCode)) {
brGeneralInfoDto.setBookingOfficeCode(officeCode);
return;
}
}
wolfie
    13
wolfie  
   2021-10-21 14:20:26 +08:00
在 Optional 基础上,定义一个 OptionalWrapper 。

OptionalWrapper<T> or(Supplier<T> supplier)

可以链式调用。
Guiyanakuang
    14
Guiyanakuang  
   2021-10-21 14:23:14 +08:00
为了保证可读性不建议抽取保存到 list 里,只需要将重复部分独立为单个函数,每个函数返回 this,链式调用逻辑更清晰
wolfie
    15
wolfie  
   2021-10-21 14:31:14 +08:00   3
```
class OptionalChain<T> {

private T value;

private OptionalChain(T val) {
value = val;
}

public static <T> OptionalChain<T> of(Supplier<T> supplier) {
return new OptionalChain<>(supplier.get());
}

public OptionalChain<T> or(Supplier<T> supplier) {
if (value == null) {
value = supplier.get();
}
return this;
}

public T get() {
return value;
}

}
```
hingbong
    16
hingbong  
   2021-10-21 16:30:40 +08:00
```
public OptionalChain<T> or(Predicate<T> predicate, Supplier<T> supplier) {
if (predicate.test()) {
return this;
}
value = supplier.get();
}```
判断条件也动态起来?
fkdog
    17
fkdog  
   2021-10-21 16:30:43 +08:00
将所有的 getOfficeCodeByXXX()包装成 Function,然后塞进一个 List 。
做 list 的迭代,执行 function.apply(),如果返回值非空,则 break 跳出迭代。

``` java
List<Function<BrChangedEvent,String>> funcs= Arrays.asList(
XXX::getOfficeCodeByOfficeUnlLocCode,
XXX::getOfficeCodeByPor,
XXX::getOfficeCodeByFnd,
XXX::getOfficeCodeByPol);
for(Function<BrChangedEvent,String> func:funcs){
String officeCode = func.apply(brGeneralInfoDto);
if(String.isNotEmpty(officeCode)){
brGeneralInfoDto.setBookingOfficeCode(officeCode);
}
}
```
NeroKamin
    18
NeroKamin  
   2021-10-21 17:10:37 +08:00
@wolfie 第一直觉也是把 function 放到 list 遍历,再看这个链式调用,明显感觉要好很多
yazinnnn
    19
yazinnnn  
   2021-10-21 20:05:04 +08:00
functions.stream()
.parallel()
.map(it -> it.apply(""))
.filter(StringUtils::isNotBlank)
.findFirst()
.orElse("");

这样?
itechify
    20
itechify  
PRO
   2021-10-21 20:54:46 +08:00 via Android
remark,这样优化也有意义也有意思,后面再添加就不断的 append 进去
crclz
    21
crclz  
   2021-10-21 22:19:07 +08:00
初始实现没啥问题,第二版过拟合了(现在最简,但是不能很好应对新需求)
bxb100
    22
bxb100  
   2021-10-21 22:40:45 +08:00
可以考虑使用责任链设计模式
jorneyr
    23
jorneyr  
   2021-10-21 23:04:15 +08:00
if 已经是最优解了,其他各种花哨的办法难看的要死。
关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2542 人在线   最高记录 6679       Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 25ms UTC 04:36 PVG 12:36 LAX 21:36 JFK 00:36
Do have faith in what you're doing.
ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86