Fastjson源码阅读:缺陷静态检查(上)

缺陷静态检查 2897

使用工具QAPlug(包含Checkstyle FindBgus PMD)

静态代码检查

缺陷修改意见主要参考:stackoverflow

前言

使用QAPlug工具进行分析,将缺陷主要分为效能、可移植性、可靠性、可维护性、可用性五个方面。本文将分两篇来简单分析代码中缺陷的成因以及解决方案。第一篇将从效能、可移植性、可靠性三方面入手,对每一个错误类型都会给出一个典型的修改案例或意见。
在这里插入图片描述

效能 22

Hide Utility Class Constructor 3

工具类应该隐藏public构造器

在这里插入图片描述

如果该类仅是实用程序类,那么应该将该类定型并定义一个私有构造函数

这样可以防止默认的无参数构造函数在代码的其他地方使用。此外,还可以将类定型,这样它就不能在子类中进行扩展,这是实用程序类的最佳实践。由于仅声明了一个私有构造函数,因此其他类将无法对其进行扩展,但是将类标记为final仍然是一种最佳实践。

举例

/*
将该类标记为final,以使Sonar(代码检查工具)实际考虑已解决的违规情况。仅添加私有构造函数并不能清除冲突。
*/
public class ServiceLoader {
    // 省略...
    private ServiceLoader(){
        // 不调用
    }
    // 省略...
}

Unnecessary Local Before Return 19

返回之前不用的本地变量

在这里插入图片描述

举例:

// 修改前
public static final int writeJSONString(OutputStream os, // 
                                             Charset charset, // 
                                             Object object, // 
                                             SerializeConfig config, //
                                             SerializeFilter[] filters, //
                                             String dateFormat, //
                                             int defaultFeatures, //
                                             SerializerFeature... features) throws IOException {
        SerializeWriter writer = new SerializeWriter(null, defaultFeatures, features);

        try {
            // 省略...
            
            // 修改前
            int len = writer.writeToEx(os, charset);
            return len;
            // 修改为 return writer.writeToex(os, charset)
        } finally {
            writer.close();
        }
    }

可移植性 1

Replace Hashtable With Map 1

用Map替换Hashtable

在这里插入图片描述

public Map<Object, Object> createMap(Type type, int featrues) {
        if (type == Properties.class) {
            return new Properties();
        }

        if (type == Hashtable.class) {
            return new Hashtable();
            // 替换为 return new Map();
        }

        if (type == IdentityHashMap.class) {
            return new IdentityHashMap();
        }

        if (type == SortedMap.class || type == TreeMap.class) {
            return new TreeMap();
        }
    // 省略...
}

可靠性 1597

Avoid Catching Throwable 48

避免捕获Throwable

在这里插入图片描述

举例:

在catch里抛出Throwable里不被推荐,因为它的范围极其广泛,这个包含了一些运行时异常,如OutOfMemoryError内容溢出,而这些错误应该被单独管理。

因此具体问题具体分析,请指明具体异常

Clone Throws Clone Not Supported Exception 3

clone方法应该抛出CloneNotSupportedException

在这里插入图片描述

举例:

// 原
public Object clone() {
        return new JSONArray(new ArrayList<Object>(list));
}
// 修改后
public Object clone() throws CloneNotSupportedException {
        return new JSONArray(new ArrayList<Object>(list));
}

Close Resource 11

关闭资源

在这里插入图片描述

应该确保资源在使用后关闭 比如InputStream

举例:

public static <T> T parseObject(byte[] bytes, int offset, int len,
                                    Charset charset,
                                    Type clazz,
                                    ParserConfig config,
                                    ParseProcess processor,
                                    int featureValues,
                                    Feature... features) {
        // ...
        if (charset == IOUtils.UTF8) {
            // ...

            if (chars_len < 0) {
                InputStreamReader gzipReader = null;
                try {
                    gzipReader = new InputStreamReader(
                            new GZIPInputStream(
                                    new ByteArrayInputStream(bytes, offset, len)), "UTF-8");
                    // ...
                } catch (Exception ex) {
                    return null;
                } finally {
                    // ...
                    // 新增gzipReader.close()  //此处应该记得抛出IO异常
                }
            }
			// ...
    }

Compare Objects With Equals 30

应该用equals方法来比较对象

在这里插入图片描述

对于对象的引用应该使用equals方法,原因懂的都懂,不过多赘述。

举例:

static class FloorSegment implements Segment {
        public final static FloorSegment instance = new FloorSegment();
        public Object eval(JSONPath path, Object rootObject, Object currentObject) {
            if (currentObject instanceof JSONArray) {
                JSONArray array = ((JSONArray) ((JSONArray) currentObject).clone());
                for (int i = 0; i < array.size(); i++) {
                    Object item = array.get(i);
                    Object newItem = floor(item);
                    if (newItem != item) {
                    //此处判断应修改为 !newItem.equals(item)
                        array.set(i , newItem);
                    }
                }
                return array;
            }

            return floor(currentObject);
        }

Constructor Calls Overridable Method 16

在构造方法中调用覆写的方法不妥当,存在风险

在这里插入图片描述

有风险。构造方法调用不是原子的,因此,如果在另一个线程中调用实例方法,那么从构造方法推迟实例方法的调用也同样安全,因为不能保证在(最终)调用线程时完全构造对象。
现在,假设,如果子类对象被完全构造(重点是假设),那么未来的回调将是安全的。换句话说,它不会绕过部分构造的对象,这与其说是危险的,还不如说是访问它。

这是有风险的,因为在完全构建测试对象之前,会将它暴露给第二个线程。
如果需要通过调用hello来控制测试实例的初始化,请考虑使用工厂方法进行实例化。将其与私有构造方法相结合,可以保证在所有测试对象上安全地调用hello:

Design For Extension 270

在这里插入图片描述

如果类不是为扩展而设计的,考虑将类final或使方法’write’ static/final/abstract/empty,或为方法添加允许的

Magic Number 1194

魔数:代码中出现的没有说明的数字

在这里插入图片描述

具体问题具体分析,FastJson中的魔数主要表现在1024、0xff以及设计特殊需要 没啥好说的

Security Array is stored directly 24

在这里插入图片描述

一般是数组浅拷贝和深拷贝的问题

举例:

public Context(FieldInfo[] getters, //
                       SerializeBeanInfo beanInfo, //
                       String className, //
                       boolean writeDirect, //
                       boolean nonContext){
            this.getters = getters;
    		// 改为 this.getters = Arrays.copyOf(getters, getters.length)
            this.className = className;
            this.beanInfo = beanInfo;
            this.writeDirect = writeDirect;
            this.nonContext = nonContext || beanInfo.beanType.isEnum();
        }

String Literal Equality 1

字符串比较应使用equals

在这里插入图片描述

字符串应使用equals()方法进行比较,而非’==’。

if ("$ref" == key && context != null) {
    // 修改为"$ref".equals(key)
    // ...
}

最后

该文章仅用于学习记录及交流,若有错误还望理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值