排序有两种

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)

java学习-排序及加密签名时数据排序方式的更多相关文章

  1. Java虚拟机 - 结构原理与运行时数据区域

    http://liuwangshu.cn/java/jvm/1-runtime-data-area.html 前言 本来计划要写Android内存优化的,觉得有必要在此之前介绍一下Java虚拟机的相关 ...

  2. java学习总结篇二--3 种简单排序

    本篇文章,先从数据结构开始,一边总结,一边反思,寻求最优解. 本文简单温习下最基础的三类算法:选择,冒泡,插入.先定义一个交换数组作为备用: /** * 交换数组元素 * @param arr * @ ...

  3. [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义

    前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine  ,既然是虚拟机, ...

  4. 《深入理解Java虚拟机》笔记01 -- 运行时数据区

    运行时数据区示意图 1. 程序计数器 占用一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器.主要用来记录线程执行到哪条语句了,分支.循环.跳转.异常处理.线程恢复等功能都需要依赖这个 ...

  5. JVM学习一:JVM运行时数据区

    注:此图适合JDK 7之前的版本,JDK 8开始增加了元数据空间,内存区结构有所变化(JDK 7将字符串常量池移除了永久代,JDK 8去永久代,迎元数据空间metaspace) 1.程序计数器:程序计 ...

  6. java学习笔记(二)之数据部分

    数据类型 java数据类型 基本数据类型 数值型 整型byte/short/int/long   浮点型/double/float   字符型char     布尔型boolean 取值true  f ...

  7. Java学习笔记:输入、输出数据

    相关内容: 输出数据: print println printf 输入数据: Scanner 首发时间:2018-03-16 16:30 输出数据: JAVA中在屏幕中打印数据可以使用: System ...

  8. java学习笔记 (2) —— Struts2类型转换、数据验证重要知识点

    1.*Action.conversion-properties 如(point=com.test.Converter.PointListConverter) 具体操作类的配置文件 2.*Action. ...

  9. java学习之—合并两个数组并排序

    /** * 合并两个数组并排序 * Create by Administrator * 2018/6/26 0026 * 下午 4:29 **/ public class MergeApp { pub ...

随机推荐

  1. VS2013利用ajax访问不了json文件——VS2013配置webconfig识别json文件

    这两天用VS2013开发工具来访问json文件,老是报404文件,我根据网上来设置IIS添加MIME重启IIS和VS2013还是失败,无法访问json文件,但是奇怪的是可以访问txt文件 查询了很多方 ...

  2. 【repost】Javascript操作DOM常用API总结

    Javascript操作DOM常用API总结 文本整理了javascript操作DOM的一些常用的api,根据其作用整理成为创建,修改,查询等多种类型的api,主要用于复习基础知识,加深对原生js的认 ...

  3. bzoj 2440 完全平方数 【莫比乌斯函数】

    题目 题意:第Ki 个不是完全平方数的正整数倍的数. 对于一个数t,t以内的数里的非完全平方数倍数的个数:num=1的倍数的数量−一个质数平方数(9,25,49...)的倍数的数量+两个质数的积平方数 ...

  4. ASP.NET Web API 框架研究 Action方法介绍

    在根据请求解析出匹配的Controller类型并创建实例后,要在该Controller类型中的众多Action方法中选择与请求匹配的那一个,并执行,然后返回响应. Action方法,其元数据,主要包括 ...

  5. 前端开发 - JavaScript

    本节内容 一.如何编写 二.变量 三.数据类型 四.其他 五.语句与异常 六.函数 JavaScript是一门编程语言,浏览器内置了JavaScript语言的解释器,所以在浏览器上按照JavaScri ...

  6. TVS二极管

    TVS管命名规则: TVS管的型号由三部分组成:系列名+电压值+单/双向符号 系列名代表不同的峰值脉冲功率和封装形式     ① SMAJ.SMBJ.SMCJ.SMDJ表示贴片封装:分别代表的峰值脉冲 ...

  7. Delphi 内进行音量控制及静音

    unit UMute; interface uses MMSystem, Dialogs; Type   TDeviceName = (Master, Microphone, WaveOut, Syn ...

  8. 自动化构建工具gradle安装教程(使用sdkman安装)

    gradle是什么?(wiki解释) Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具.它使用一种基于Groovy的特定领域语言来声明项目设置,而不是传统的 ...

  9. JS学习笔记3_函数表达式

    1.函数表达式与函数声明的区别 函数声明有“提升”(hoisting)的特性,而函数表达式没有.也就是说,函数声明会在加载代码时被预先加载到context中,而函数表达式只有在执行表达式语句时才会被加 ...

  10. Spring AOP 源码分析 - 创建代理对象

    1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...