List list = Arrays.asList(1,232,3,2,4,3,534,57,56,8,567,7,45,321,4,234,23,5,45,7,6,978,4,523,4,21,3,45,7,69,8,54,623,45,23,4,34,656,89,7689,56,23,4,234,23,5,456,5,467,67,8,4,5,34,345,45,6,324,3,46,568,789,78,56,3,45,34,5,47,6,9,5,2345,45,7,67,9,6789,6,34,52,346,56,8,789,67,423,4,23,5,345,34,6,4,12,3,123,54,56,546,7,56,8756,78,67,8,67,45,6,3,423,14,12,34,324,56,47,56,78,567,8,5,634,25,123,4,3,57,89,789,65,63,1,24,3,46,68,67,8,4,5,1235,45,7,67,8,66,312,5,458,678,9,64);
System.out.println(list);
Long begin=System.currentTimeMillis();
//方法一:使用java8新特性stream进行List去重
List newList = (List)list.stream().distinct().collect(Collectors.toList());
System.out.println("java8stream去重:"+newList.size() +" left ,Time-cost:"+(System.currentTimeMillis()-begin)+" ms.");
//方法2:set集合判断去重,不打乱顺序
Set set1 = new HashSet();
List newList1 = new ArrayList();
for (Object integer : list) {
if(set1.add(integer)) {
newList1.add(integer);
}
}
System.out.println("set集合判断去重:"+newList1.size() +" left ,Time-cost:"+(System.currentTimeMillis()-begin)+" ms.");
//方法3:遍历后判断赋给另一个list集合
List newList2 = new ArrayList();
for (Object integer : list) {
if(!newList2.contains(integer)){
newList2.add(integer);
}
}
System.out.println("赋值新list去重:"+newList2.size() +" left ,Time-cost:"+(System.currentTimeMillis()-begin)+" ms.");
//方法4:set和list转换去重
Set set2 = new HashSet();
List newList3 = new ArrayList();
set2.addAll(list);
newList3.addAll(set2);
System.out.println("set和list转换去重: "+newList3.size() +" left ,Time-cost:"+(System.currentTimeMillis()-begin)+" ms.");
这里主要介绍复杂类型去重与简单类型去重的区别,首先需要知道的是简单类型的存储与使用其实是共享的,即下面的代码:
int i=127;
int j=127;
其实i与j指向的是同一个内存地址存储的值。(这里就不深入讲Interger类型在封包解包的操作中与i的差别或者String类型使用的差别了)
当对i,j进行==比较时,其实比较的是两个变量的内存地址,由于基础类型的存储特性,显然同样的值也就意味着同样的内存地址;
而当使用Equals()方法对对象进行比较时,就不一样了,默认的Object.Equals()方法使用的仍然是 == 比较即内存地址比较,
但在复杂对象的比较重,比较内存地址一般是无意义的,我们关注的是对象的类型或对象容纳值的等同意义。
因此在复杂类型的比较中我们往往会重写Equals()方法,为了提高比较的效率,又需要使用或重写HashCode()方法;
为了提高"比较"这件事的可复用性,即如果我们需要或可能需要支持多种比较规则,并支持排序等操作的话,我们就可以通过实现Comparable接口来进行对象的比较。
@Override
public boolean equals(Object arg0) {
// TODO Auto-generated method stub
People p = (People) arg0;
return name.equals(p.name) && phoneNumber.equals(p.phoneNumber);
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
String str = name + phoneNumber;
return str.hashCode();
}
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
比较两个对象时,首先先去判断两个对象是否具有相同的地址,如果是同一个对象的引用,则直接放回true;如果地址不一样,则证明不是引用同一个对象,接下来就是挨个去比较两个字符串对象的内容是否一致,完全相等返回true,否则false。
hashCode()
public int hashCode() {
int h = hash;
if (h == 0 && count > 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
1. 对象实现Comparable接口,
2. 重写compareTo方法,
public class Man implements Comparable{
//TODO 中间代码省略
@Override
public int compareTo(Man m) {
return this.age-m.age; // 0等于,>0大于, <0小于
}
}
3.排序
Collections.sort(manList);
对任意类型集合对象进行整体排序,排序时将此接口的实现传递给Collections.sort方法或者Arrays.sort方法排序.
实现int compare(T o1, T o2);方法,返回正数,零,负数各代表大于,等于,小于。
单一条件排序:(多条件无非是在s1,s2第一个条件相等时再嵌套一层对于第二个条件的判断,其实都一样)
举例:
List stus = new ArrayList(){
{
add(new Student("张三", 30));
add(new Student("李四", 20));
add(new Student("王五", 60));
}
};
//对users按年龄进行排序
Collections.sort(stus, new Comparator() {
@Override
public int compare(Student s1, Student s2) {
// 升序
//return s1.getAge()-s2.getAge();
return s1.getAge().compareTo(s2.getAge());
// 降序
// return s2.getAge()-s1.getAge();
// return s2.getAge().compareTo(s1.getAge());
}
});
// 输出结果
...
注: 还可以使用lambda表达式简化代码, 前提是JDK8开发环境, 如下:
List stus = new ArrayList(){
{
add(new Student("张三", 30));
add(new Student("李四", 20));
add(new Student("王五", 60));
}
};
//对users按年龄进行排序
Collections.sort(stus, (s1,s2)->(s1.getAge()-s2.getAge()));