【进阶之路】操作日志、加解密与嵌套循环优化

2021-04-02 11:25:26 浏览数 (3)

.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:15px;overflow-x:hidden;color:#333}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:30px;margin-bottom:5px}.markdown-body h2{padding-bottom:12px;font-size:24px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:18px;padding-bottom:0}.markdown-body h4{font-size:16px}.markdown-body h5{font-size:15px}.markdown-body h6{margin-top:5px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:""}.markdown-body blockquote>p{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body ul li{margin-bottom:0;list-style:inherit}.markdown-body ol li .task-list-item,.markdown-body ul li .task-list-item{list-style:none}.markdown-body ol li .task-list-item ol,.markdown-body ol li .task-list-item ul,.markdown-body ul li .task-list-item ol,.markdown-body ul li .task-list-item ul{margin-top:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:3px}.markdown-body ol li{padding-left:6px}.markdown-body .contains-task-list{padding-left:0}.markdown-body .task-list-item{list-style:none}@media (max-width:720px){.markdown-body h1{font-size:24px}.markdown-body h2{font-size:20px}.markdown-body h3{font-size:18px}}

导言

大家好,我是南橘,从接触java到现在也有差不多两年时间了,两年时间,从一名连java有几种数据结构都不懂超级小白,到现在懂了一点点的进阶小白,学到了不少的东西。知识越分享越值钱,我这段时间总结(包括从别的大佬那边学习,引用)了一些平常学习和面试中的重点(自我认为),希望给大家带来一些帮助

之前的文章

【进阶之路】Java代码性能调优(一) 【进阶之路】Java代码性能调优(二) 【进阶之路】Java代码性能调优-基准测试工具JMH(三)

有需要的同学可以加我的公众号,以后的最新的文章第一时间都在里面,也可以找我要思维导图

一、后台操作日志记录

最近在工作中涉及到一些关于后台信息修改的日志内容记录,涉及到多个表与多个类数据的修改,获取对象的属性成了一个比较麻烦的事情。 同时,因为不知道每次具体修改的对象的信息,为了减少代码量,所以我用到反射来动态的获取对象的属性。

1、实体类操作记录

下面的代码是利用反射来获取对象属性值变化的比较简单的一种实践,倒也能帮助实现对比,但是遇到数据里包含数组的情况却还是有些吃力。

代码语言:javascript复制
    /**
     * @param oldBean 原始数据
     * @param newBean 新数据
     * @return
     */
    public static String contrastSourceFund(Object oldBean, Object newBean) {
        String str = "";

        Object pojo1 = (Object) oldBean;
        Object pojo2 = (Object) newBean;
        try {
            Class clazz = pojo1.getClass();
            Field[] fields = pojo1.getClass().getDeclaredFields();
            int i = 1;
            for (Field field : fields) {
                if("serialVersionUID".equals(field.getName())) {
                    continue;
                }
                PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                Method getMethod = pd.getReadMethod();
                    Object o1 = getMethod.invoke(pojo1);
                    Object o2 = getMethod.invoke(pojo2);
                    if(o2 == null) {
                        continue;
                    }else if(o1 == null){
                     //对字段进行转义
                        String getName = strChange(field.getName());
                        str  = getName   ":新增值:"   o2;
                        i  ;
                    }else{
                        if(o1.getClass().getName().equals("java.math.BigDecimal")) {
                            o1 = ((BigDecimal) o1).stripTrailingZeros().toPlainString();
                        }
                        if(o2.getClass().getName().equals("java.math.BigDecimal")) {
                            o2 = ((BigDecimal) o2).stripTrailingZeros().toPlainString();
                        }
                        if(!o1.equals(o2)) {

                            if(i != 1) {
                                str  = "|";
                            }
                            //对字段进行转义
                            String getName = strChange(field.getName());
                            str  = getName   ":旧值:"   o1   ",新值:"   o2;
                            i  ;
                        }
                    }

                }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

2、集合类数据操作记录

这里可以用到一些简单的方法对传入的集合数据进行分类,当然,数据传入之前肯定要相应地进行一些格式化,同时代码还可以继续抽象,最好能把工具类和业务代码完全抽象出来,但是我这边就不继续往下实现了,各位同学可以自己进一步抽象。

代码语言:javascript复制
  /**
         *对资金产品信息进行比较
         */
        if(!newSource.getProdList().equals(oldSource.getProdList())) {

            List incProdList = getAddaListThanbList(newSource.getProdList(), oldSource.getProdList());
            List decProdList = getReduceaListThanbList(newSource.getProdList(), oldSource.getProdList());
            if(incProdList.size() != 0) {
                recordSourceFundLog.append("新增资金产品信息:"   incProdList).append("#");
            }

            if(decProdList.size() != 0) {
                recordSourceFundLog.append("减少资金产品信息:"   decProdList).append("#");
            }
        }
 /**
     * 计算列表aList相对于bList的增加的情况,兼容任何类型元素的列表数据结构
     *
     * @param aList 新列表
     * @param bList 旧列表
     * @return 返回增加的元素组成的列表
     */
    public static  List getAddaListThanbList(List aList, List bList) {
        List addList = new ArrayList();
        for (int i = 0; i < aList.size(); i  ) {
            if(!myListContains(bList, aList.get(i))) {
                addList.add(aList.get(i));
            }
        }
        return addList;
    }
    
    /**
     * 判断元素element是否是sourceList列表中的一个子元素
     *
     * @param sourceList 源列表
     * @param element    待判断的包含元素
     * @return 包含返回 true,不包含返回 false
     */
    private static  boolean myListContains(List sourceList, E element) {
        if(sourceList == null || element == null) {
            return false;
        }
        if(sourceList.isEmpty()) {
            return false;
        }
        for (E tip : sourceList) {
            if(element.equals(tip)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 计算列表aList相对于bList的减少的情况,兼容任何类型元素的列表数据结构
     *
     * @param aList 新列表
     * @param bList 旧列表
     * @return 返回减少的元素组成的列表
     */
    public static  List getReduceaListThanbList(List aList, List bList) {
        List reduceaList = new ArrayList();
        for (int i = 0; i < bList.size(); i  ) {
            if(!myListContains(aList, bList.get(i))) {
                reduceaList.add(bList.get(i));
            }
        }
        return reduceaList;
    }

以上的几种方法可以结合起来,我在实现最后的日志记录的时候,就是将这些操作代码根据业务场景进行了结合,同时大家也可以考虑用AOP来实现这些方法,不过个人感觉用处不大,对后台操作的记录只在一些特殊情况需要用到。

二、 加解密

在接口的调用过程中,特别是在客户端与服务器进行交互时,必然涉及到交互的报文(请求数据与返回数据),如果不希望报文进行明文传输,则需要进行报文的加密与解密。所以加密的主要作用就是避免明文传输,就算被截获报文,截获方也不知道报文的具体内容。

这次与之前做加解密有些不一样,用到的是RSA加密。

RSA加密:非对称密钥,公开密钥算法

RSA加密利用了单向函数正向求解很简单,反向求解很复杂的特性。具体原理我也不知道,同学们真的感兴趣可以去网上查一下~

里面的具体内容可以不看,但是总体的加密流程就是这样,代码的话网上也是有各式各样的,大家可以根据流程来对代码进行完善。

三、循环优化

1、嵌套循环

此外,这段时间还对之前的代码做了一段重构,大家都知道,在嵌套循环中应该遵循外小内大的原则,这样性能才会高。

代码语言:javascript复制
 long  startTimeDa =  System.nanoTime();
        for (int  i=0;i<100_00_0;i  ){
            for (int j=0;j<10;j  ){
            }
        }
        long  endTimeDa =  System.nanoTime();
        System.out.println("外大内小:" (endTimeDa-startTimeDa));

        long  startTimeXiao =  System.nanoTime();
        for (int  i=0;i<10;i  ){
            for (int j=0;j<100_00_0;j  ){
            }
        }
        long  endTimeXiao =  System.nanoTime();
        System.out.println("外小内大:" (endTimeXiao-startTimeXiao));

外大内小:4416666 外小内大:11788860

但是这不是全部,在《JAVA系统性能优化实战》这本书中,155页降到了JTI会做Dead-Code消除,JIT会去判断循环对程序是否有任何影响,从而消除循环体的影响、

2、JIT

为什么JIT能消除影响呢?

举个例子:

同样两个演员C和AB,C拿到剧本以后,演戏前先看剧本,然后写大纲做思维导图,然后再开始演戏。

AB就不一样了,AB拿着就开始演,不会了就停下看一会,看完了继续演,就来回折腾。

在主流商用JVM(HotSpot、J9)中,Java程序一开始是通过解释器(Interpreter)进行解释执行的。当JVM发现某个方法或代码块运行特别频繁时,就会把这些代码认定为“热点代码(Hot Spot Code)”,然后JVM会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为:即时编译器(Just In Time Compiler,JIT)

JIT编译器是“动态编译器”的一种。

当然,不管有没有JIT,我们自己在编写代码的过程中,遵循外小内大的原则总是没有错的。

0 人点赞