zoukankan      html  css  js  c++  java
  • java学习-排序及加密签名时数据排序方式

    排序有两种

    1. 类实现comparable接口调用List.sort(null)或Collections.sort(List<T>)方法进行排序

    jdk内置的基本类型包装类等都实现了Comparablel接口,默认是使用自然排序,即升序排序

    自定义类实现Comparable接口必须要实现compareTo()方法,自己定义排序方式

    2.另一种是List<T>中T类没有实现comparable接口,又想将对象列表进行排序时,类似于Collections.sort or Arrays.sort排序时候使用Comparator接口作为参数进行集合的排序

    上面的两种排序方式底层都是采用归并排序算法,是稳定的排序算法。时间复杂度(nlog2n),空间复杂度(n) 十大经典排序算法(动图演示)

    使用场景:

    1.调用别人接口获取数据时候,需要将参数按照字典排序排序对数据进行签名,与返回的签名数据进行对比,验证数据的完整性。

    2.对获取的数据进行排序后返回给前端,除了使用sql的order asc命令外,也可以使用list.sort方法进行排序后返回给前端(有点傻^^)。

    3. 用于复杂的排序场景,比如文件名的排序,广东-广州-期末测试1,广西-桂林-期末测试2,需要我们自己控制排序方法,这时候就需要用到上面两个排序。

    实现Comparable接口的排序

    consumInfo.java类

    实现comparable接口,使用升序排序

    降序就是取反

    if (this.price > o.price) {
                return -1;
            }
            if (this.price == o.price) {
                return 0;
            }
            return 1;
    public class ConsumInfo implements Comparable<ConsumInfo> {
        public double price;
        public String name;
    
        public ConsumInfo(double price, String name) {
            super();
            this.price = price;
            this.name = name;
        }
    
        @Override
        public int compareTo(ConsumInfo o) {
            // 首先比较price,如果price相同
    
            if (this.price > o.price) {
                return 1;
            }
    
            if (this.price == o.price) {
                return 0;
            }
    
            return -1;
        }
    }

    来个简单的测试

            ConsumInfo []cc=new ConsumInfo[4];
            cc[0] = new ConsumInfo(1.1, "zwh");
            cc[1] = new ConsumInfo(2.5, "abc");
            cc[2] = new ConsumInfo(0.1, "zwh");
            cc[3] = new ConsumInfo(0.1, "cdf");
            Arrays.sort(cc);
            for(ConsumInfo consumInfo:cc) {
                System.out.println("name:"+consumInfo.name+"  price:"+consumInfo.price);
            }
    结果

    name:zwh price:0.1
    name:cdf price:0.1
    name:zwh price:1.1
    name:abc price:2.5

     

    如果要先按照price排序,如果price相等,再按name进行升序排序呢

    只需要修改conpareTo()方法,在price相等时,在比较name的值

        @Override
        public int compareTo(ConsumInfo o) {
            // 首先比较price,如果price相同
    
            if (this.price > o.price) {
                return 1;
            }
            
            if(this.price==o.price) {
                return this.name.compareTo(o.name);
            }
    
            return -1;
        }

    修改后的输出结果,

    这里name是String类型,默认是按照字典顺序排序,也就是升序排序。

    cdf和zwh,,c比z小,所以调换了位置

    name:cdf  price:0.1
    name:zwh  price:0.1
    name:zwh  price:1.1
    name:abc  price:2.5

    使用Comparator接口实现排序 

    还是使用上面的ConsumInfo.java类

            ConsumInfo []cc=new ConsumInfo[4];
            cc[0] = new ConsumInfo(1.1, "zwh");
            cc[1] = new ConsumInfo(2.5, "abc");
            cc[2] = new ConsumInfo(0.1, "zwh");
            cc[3] = new ConsumInfo(0.1, "cdf");
            Arrays.sort(cc,new Comparator<ConsumInfo>() {
    
                @Override
                public int compare(ConsumInfo o1, ConsumInfo o2) {
                    if(o1.price<o2.price) {
                        return -1;
                    }
                    if(o1.price==o2.price) {
                        return o1.name.compareTo(o2.name);
                    }
                    return 1;
                }
            });
            for(ConsumInfo consumInfo:cc) {
                System.out.println("name:"+consumInfo.name+"  price:"+consumInfo.price);
            }

    使用了Arrays.sort(T[] a, Comparator<? super T> c)排序方法,会把ConsumInfo所实现的Comparable接口的排序方法替换掉

    也就是说只会使用Comparator接口进行排序。

    上面的排序是用于List或者数组或集合的排序,

    对于Map,需要对map的key值进行升序排序

    使用TreeMap类进行自动排序,默认升序排序。

            Map<String, String> para = new TreeMap<String, String>();
            para.put("zwh", "123456");
            para.put("abc", "123456");
            para.put("wuv", "123456");
            para.put("cdg", "123456");
    
            for (Map.Entry<String, String> entry : para.entrySet()) {
                System.out.println("key:" + entry.getKey() + " value:" + entry.getValue());
            }
    结果

    key:abc value:123456
    key:cdg value:123456
    key:wuv value:123456
    key:zwh value:123456

     

    或者我们自己手动对map的key值进行排序 参考:【支付宝,微信支付必备】Java实现url参数按照参数名Unicode码从小到大排序(字典序)

    /** 
        *  
        * 方法用途: 对所有传入参数按照字段名的Unicode码从小到大排序(字典序),并且生成url参数串<br> 
        * 实现步骤: <br> 
        *  
        * @param paraMap   要排序的Map对象 
        * @param urlEncode   是否需要对value的值进行编码
        * @param keyToLower    是否需要将Key转换为全小写 
        *            true:key转化成小写,false:不转化 
        * @return 
        */
        public static String formatUrlMap(Map<String, String> paraMap, boolean urlEncode, boolean keyToLower) {
            String buff = "";
            Map<String, String> tmpMap = paraMap;
            try {
                List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(tmpMap.entrySet());
                // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
                Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
    
                    @Override
                    public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
                        return (o1.getKey()).toString().compareTo(o2.getKey());
                    }
                });
                // 构造URL 键值对的格式
                StringBuilder buf = new StringBuilder();
                for (Map.Entry<String, String> item : infoIds) {
                    if (item.getKey() != null) {
                        String key = item.getKey();
                        String val = item.getValue();
                        if (urlEncode) {
                            val = URLEncoder.encode(val, "utf-8");
                        }
                        if (keyToLower) {
                            buf.append(key.toLowerCase() + "=" + val);
                        } else {
                            buf.append(key + "=" + val);
                        }
    
                        buf.append("&");
                    }
    
                }
                buff = buf.toString();
                if (buff.isEmpty() == false) {
                    buff = buff.substring(0, buff.length() - 1);
                }
            } catch (Exception e) {
                return null;
            }
            return buff;
        }

    参考支付宝的参数排序方法

    剔除sign字段(这个根本不需要剔除,参数中是没有的),

    剔除参数值为空的字段,这里做了个简单的判断,

    对key进行排序,然后用&符号对key=value进行拼接。

            Map<String, String> para = new TreeMap<String, String>();
            para.put("app_id", "2014072300007148");
            para.put("method", "alipay.mobile.public.menu.add");
            para.put("charset", "");
            para.put("sign_type", "");
            para.put("timestamp", "2014-07-24 03:07:50");
            para.put("biz_content", "");
            para.put("sign_type", "123456");
            para.put("version", "1.0");
    
            List<String> keys= new ArrayList<>(para.keySet());
            Collections.sort(keys);
            StringBuffer content=new StringBuffer();
            for (int i=0; i<keys.size();i++) {
                String key = keys.get(i);
                String value = para.get(key);
                if(value!=null&&value.length()!=0) {
                    content.append((i==0?"":"&")+key+"="+value);
                }
            }
            System.out.println(content.toString());

    结果

    app_id=2014072300007148&method=alipay.mobile.public.menu.add&sign_type=123456&timestamp=2014-07-24 03:07:50&version=1.0

     

    注意,上面字符串的空判断还少做了一个空白字符的判断,建议使用下面的值的非空判断代替

    if(value!=null&&value.length()!=0)
    public static boolean isBlank(String str) {
            int strLen;
            if (str == null || (strLen = str.length()) == 0) {
                return true;
            }
            for (int i = 0; i < strLen; i++) {
                if ((Character.isWhitespace(str.charAt(i)) == false)) {
                    return false;
                }
            }
            return true;
        }

     待看:http://www.cnblogs.com/interdrp/p/8970593.html Java Comparator字符排序(数字、字母、中文混合排序)

    编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议70~74)

  • 相关阅读:
    为什么使用Redis
    [Apache Pulsar] 企业级分布式消息系统-Pulsar快速上手
    [Apache Pulsar] 企业级分布式消息系统-Pulsar入门基础
    JDK源码分析系列---ArrayList和LinkList
    JDK源码分析系列---String,StringBuilder,StringBuffer
    单点登录
    单例模式的几种实现方式
    Bloom’S Taxonomy
    Python 字符串多替换时性能基准测试
    软件开发的生产力vs质量
  • 原文地址:https://www.cnblogs.com/gne-hwz/p/10178390.html
Copyright © 2011-2022 走看看