优雅代码 - 反向思维尽快结束

要达到反向思维,尽快结束目的,我总结下3种方式

if判断反写,尽快return或者throw(最简单,最实用)

② 减少不必要的else,能不用则不用

③ 在循环中多使用breakcontinue等流程控制方式


案例1(if反写,多用流程控制语句)
// Dubbo 源码,RegistryDirectory.destroyUnusedInvokers
// 这个方法干了啥?把old列表跟new列表做一遍比对,把new列表中不存在元素,都做destory操作。也就是,循环old列表,然后逐个看new列表有没有,没有就记录到删除列表,然后循环删除列表逐个做destory操作-

    if (createAdaptiveInstanceError != null) {// 反向判断,尽快return,思路更加清晰明了
        throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
    }

    synchronized (cachedAdaptiveInstance) {
        instance = cachedAdaptiveInstance.get();
        if (instance != null) {// 反向判断,尽快return,思路更加清晰明了
            return (T) instance;
        }
        try {
            instance = createAdaptiveExtension();
            cachedAdaptiveInstance.set(instance);
        } catch (Throwable t) {
            createAdaptiveInstanceError = t;
            throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
        }
    }
    return (T) instance;
}

案例4(if反写,多用流程控制语句)
// Dubbo 源码,ExtensionLoader.injectExtension
private T injectExtension(T instance) {
    try {
        if (objectFactory != null) {// 非空判断不可能throw异常,是否可以放到外面,并且反向判断
            for (Method method : instance.getClass().getMethods()) {
              	// 这个if有3个条件,是否可以单独提取出来,并且反向判断
                if (method.getName().startsWith("set")
                        && method.getParameterTypes().length == 1
                        && Modifier.isPublic(method.getModifiers())) {
                    Class<?> pt = method.getParameterTypes()[0];
                    try {
                        String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                        Object object = objectFactory.getExtension(pt, property);
                        if (object != null) {
                            method.invoke(instance, object);
                        }
                    } catch (Exception e) {
                        logger.error("fail to inject via method " + method.getName()
                                + " of interface " + type.getName() + ": " + e.getMessage(), e);
                    }
                }
            }
        }
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
    return instance;
}
// 重构后
private T injectExtension(T instance) {
    if (objectFactory == null) {// 提出来,单独判空,尽快return
        return instance;
    }

    try {
        for (Method method : instance.getClass().getMethods()) {
          	// 3个条件,单独提出boolean变量,并且从名字可以看出要判断啥东西,这个地方不怕名字过长。表意很重要
            boolean isSingleParamPublicSetMethod = method.getName().startsWith("set")
                    && method.getParameterTypes().length == 1
                    && Modifier.isPublic(method.getModifiers());
            if (!isSingleParamPublicSetMethod) {// 反向判断,阅读时会很容易理解,要不然得仔细阅读3个条件,还要适当猜一猜。不满足条件直接continue换下一个,简单明了。
                continue;
            }

            Class<?> pt = method.getParameterTypes()[0];
            try {
                String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                Object object = objectFactory.getExtension(pt, property);
                if (object != null) {// 这个地方没有再反写,是因为没有这个必要了,反写了也得不到啥特别的好处。适当平衡。
                    method.invoke(instance, object);
                }
            } catch (Exception e) {
                logger.error("fail to inject via method " + method.getName()
                        + " of interface " + type.getName() + ": " + e.getMessage(), e);
            }
        }
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
    return instance;
}

案例5(if反写)
// Dubbo 源码,ExtensionLoader.isMatchGroup
// 这个案例非常简单,我拿出来是想说明,编码过程要注重每一个简单的细节。
private boolean isMatchGroup(String group, String[] groups) {
    if (group == null || group.length() == 0) {
        return true;
    }
  	// 这个地方还是反写一下,会更优。
  	// 在CodeReview的时候,类似这种情况,coder就会说:我这么写没啥,也挺清晰,没必要那么计较。
  	// 是很清晰,大家也一眼就能看懂啥意思。
  	// 我想说的是,一大段复杂的代码是有由N个小的简单的代码拼凑出来的,请把每一个小的细节做到位。把每个小的细节都写的优雅了,你的整个架构,整个系统才会变得更加完美。
    if (groups != null && groups.length > 0) {
        for (String g : groups) {
            if (group.equals(g)) {
                return true;
            }
        }
    }
    return false;
}
// 重构后
private boolean isMatchGroup(String group, String[] groups) {
    if (group == null || group.length() == 0) {
        return true;
    }
    if (groups == null || groups.length == 0) {// 反写判断,直接return,大家一看就懂。
        return false;
    }
    for (String g : groups) {
        if (group.equals(g)) {
            return true;
        }
    }
    return false;
}

案例6(减少不必要的else)
// Dubbo 源码,RegistryProtocol.getFilteredKeys
// 这个类本身很简单,但是细纠,会觉得不太符合快速结束的原则
private static String[] getFilteredKeys(URL url) {
    Map<String, String> params = url.getParameters();
    if (params != null && !params.isEmpty()) {// if应该要反向判断
        List<String> filteredKeys = new ArrayList<String>();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (entry != null && entry.getKey() != null && entry.getKey().startsWith(Constants.HIDE_KEY_PREFIX)) {
                filteredKeys.add(entry.getKey());
            }
        }
        return filteredKeys.toArray(new String[filteredKeys.size()]);// 这边没有必要给长度,给一个空数组即可
    } else {// 这个else是多余的
        return new String[]{};
    }
}
// 重构后
private static String[] getFilteredKeys(URL url) {
    Map<String, String> params = url.getParameters();
    if (params == null || params.isEmpty()) {// if反写,快速结束,省略了else
        return new String[]{};
    }

    List<String> filteredKeys = new ArrayList<>();
    for (Map.Entry<String, String> entry : params.entrySet()) {
        if (entry != null && entry.getKey() != null && entry.getKey().startsWith(Constants.HIDE_KEY_PREFIX)) {
            filteredKeys.add(entry.getKey());
        }
    }
    return filteredKeys.toArray(new String[0]);
}

案例7(减少不必要的else)
// Dubbo 源码,AbstractCodec.isClientSide
// 这个案例对于else的使用有很明显,是不必要的。
protected boolean isClientSide(Channel channel) {
    String side = (String) channel.getAttribute(Constants.SIDE_KEY);
    if ("client".equals(side)) {
        return true;// 都return了,还搞啥else呢?
    } else if ("server".equals(side)) {
        return false;// 都return了,还搞啥else呢?
    } else {
        InetSocketAddress address = channel.getRemoteAddress();
        URL url = channel.getUrl();
        boolean client = url.getPort() == address.getPort()
                && NetUtils.filterLocalHost(url.getIp()).equals(
                NetUtils.filterLocalHost(address.getAddress()
                        .getHostAddress()));
        channel.setAttribute(Constants.SIDE_KEY, client ? "client"
                : "server");
        return client;
    }
}
// 重构后
protected boolean isClientSide(Channel channel) {
    String side = (String) channel.getAttribute(Constants.SIDE_KEY);
    if ("client".equals(side)) {
        return true;// 很明显,那个else是没有必要的
    }
    if ("server".equals(side)) {
        return false;// 很明显,那个else是没有必要的
    }

    InetSocketAddress address = channel.getRemoteAddress();
    URL url = channel.getUrl();
    boolean client = url.getPort() == address.getPort()
            && NetUtils.filterLocalHost(url.getIp()).equals(
            NetUtils.filterLocalHost(address.getAddress()
                    .getHostAddress()));
    channel.setAttribute(Constants.SIDE_KEY, client ? "client" : "server");
    return client;
}

案例8(减少不必要的else)
// Dubbo 源码,ExchangeCodec.encodeResponse(方法中的代码片段)
if (t instanceof IOException) {
    throw (IOException) t;
} else if (t instanceof RuntimeException) {
    throw (RuntimeException) t;
} else if (t instanceof Error) {
    throw (Error) t;
} else {
    throw new RuntimeException(t.getMessage(), t);
}
// 重构后
if (t instanceof IOException) {
    throw (IOException) t;
}
if (t instanceof RuntimeException) {
    throw (RuntimeException) t;
}
if (t instanceof Error) {
    throw (Error) t;
}
throw new RuntimeException(t.getMessage(), t);

反向思维带来的好处

① 从思维上:把正向思路无限逼近一个狭小的空间,代码越往后,分支越少,思路越明了。使其变得更加透彻。

② 从代码结构上:把代码结构和思路都变得简单,降低if for等等的层次。

注意:并不是所有时候if反写都能带来好处,要看场景,可以参考案例4中,我没有做if反写的地方。适当平衡,平衡很重要。

第5个案例非常有代表性,代码很简单,我想就此再强调下。一大段复杂的代码是有由N个小的简单的代码拼凑出来的,请把每一个小的细节做到位。把每个小的细节都写的优雅了,你的整个架构,整个系统才会变得更加完美。

全部内容查看 优雅代码汇总篇

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
public class GeneratorSqlmap { public void generator() throws Exception{ List<String> warnings = new ArrayList<String>(); boolean overwrite = true; //指定 逆向工程配置文件 File configFile = new File("generatorConfig.xml"); ConfigurationParser cp = new ConfigurationParser(warnings); Configuration config = cp.parseConfiguration(configFile); DefaultShellCallback callback = new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings); myBatisGenerator.generate(null); } public static void main(String[] args) throws Exception { try { GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap(); generatorSqlmap.generator(); } catch (Exception e) { e.printStackTrace(); } } } <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal --> <javaTypeResolver> <property name="forceBigDecimals" value="false" /> </javaTypeResolver> <!-- targetProject:生成PO类的位置 --> <javaModelGenerator targetPackage="cn.itcast.ssm.po" targetProject=".\\src"> <!-- enableSubPackages:是否让schema作为包的后缀 --> <property name="enableSubPackages" value="false" /> <!-- 从数据库返回的值被清理前后的空格 --> <property name="trimStrings" value="true" /> </javaModelGenerator> <!-- targetProject:mapper映射文件生成的位置 --> <sqlMapGenerator targetPackage="cn.itcast.ssm.mapper" targetProject=".\\src"> <!-- enableSubPackages:是否让schema作为包的后缀 --> <property name="enableSubPackages" value="false" /> </sqlMapGenerator> <!-- targetPackage:mapper接口生成的位置 --> <javaClientGenerator type="XMLMAPPER" targetPackage="cn.itcast.ssm.mapper" targetProject=".\\src"> <!-- enableSubPackages:是否让schema作为包的后缀 --> <property name="enableSubPackages" value="false" /> </javaClientGenerator> <!-- 指定数据库表 --> <table schema="" tableName="user"></table> <table schema="" tableName="orders"></table> <table schema="" tableName="items"></table> <table schema="" tableName="orderdetail"></table>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值