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

导言

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

之前的文章

【进阶之路】Java代码性能调优(一)

【进阶之路】Java代码性能调优(二)

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

一、后台操作日志记录

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

1、实体类操作记录

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

    /**
     * @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、集合类数据操作记录

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

  /**
         *对资金产品信息进行比较
         */
        if(!newSource.getProdList().equals(oldSource.getProdList())) {

            List<String> incProdList = getAddaListThanbList(newSource.getProdList(), oldSource.getProdList());
            List<String> 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 <E> List<E> getAddaListThanbList(List<E> aList, List<E> bList) {
        List<E> addList = new ArrayList<E>();
        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 <E> boolean myListContains(List<E> 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 <E> List<E> getReduceaListThanbList(List<E> aList, List<E> bList) {
        List<E> reduceaList = new ArrayList<E>();
        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、嵌套循环

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

 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

image

为什么JIT能消除影响呢?

举个例子:

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

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

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

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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358