List集合排序总结

Posted Stephen·You

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了List集合排序总结相关的知识,希望对你有一定的参考价值。

目录

问题现象

解决方法:

1、Collections.sort(java对象)

 2、Collections.sort(java对象集合, new Comparator<>() );

拓展:

3、list.stream().sorted()

拓展:

总结:

4、List排序

4.1、List的单条件升序(默认)排序

4.2、List的单条件降序排序

 4.3、List的多条件排序


问题现象

        今天在项目中相对List集合进行按需求的排序,因此打算总结一下各种情况下的List排序的代码写法?


解决方法:

自己总结了以下,list集合的排序主要有以下几种排序方式:

1、Collections.sort(java对象)

        这种方式需要满足以下条件:
        1.1、list集合中元素的数据类型是一个java对象;

        1.2、该java对象必须实现Comparable类;

        1.3、重写compareTo方法;

        其中 compareTo 方法用于指示当前元素与其他元素的比较规则,一般都是以 a - b 的形式返回int类型,表示排序规则为从 a 到 b 排序,其逻辑理解就是:如果compareTo方法返回值小于0,则当前元素往前放,大于0,则往后放。

Student实体类:

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Student implements Comparable<Student> 

	private String name;

	private int age;

	@Override
	public int compareTo(Student stu) 
		return getAge() - stu.getAge();
	

测试:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TestUtil 
	public static void main(String[] args) 
		Student stu1=new Student("小米",1);
		Student stu2=new Student("小王",2);
		Student stu3=new Student("小明",3);

		List<Student> list=new ArrayList<>();
		list.add(stu2);
		list.add(stu1);
		list.add(stu3);

		System.out.println("排序前:");
		System.out.println(list);

		System.out.println("排序后:");
		Collections.sort(list);
		System.out.println(list);
	

打印结果:

 2、Collections.sort(java对象集合, new Comparator<>() );

        这种方式与需要满足以下条件:
        1.1、list集合中元素的数据类型是一个java对象;

        1.2、重写compare方法;

Comparator 和 Comparable 的区别和理解:

Comparator 可以看成是外部比较器,因为它是先有list集合,然后再对list集合用比较器去排序;

Comparable 可以看成是内部比较器,因为它是直接在java对象实现类添加了比较器,因此是先有比较器,然后再对list集合用比较器去排序;

从上面两点,也可以推测出 Comparable 的排序算法的效率应该是比 Comparator 要高效的。

Comparator :使用了匿名内部类来构建了一个Comparator比较器对象,从而实现排序,优点是:不需要在创建java对象时,实现 Comparable 接口,缺点是效率比 Comparable  要低一些。

Student实体类:

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Student

	private String name;

	private int age;

测试:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class TestUtil 
	public static void main(String[] args) 
		Student stu1 = new Student("小米", 1);
		Student stu2 = new Student("小王", 2);
		Student stu3 = new Student("小明", 3);

		List<Student> list = new ArrayList<>();
		list.add(stu2);
		list.add(stu1);
		list.add(stu3);

		System.out.println("排序前:");
		System.out.println(list);

		System.out.println("排序后:");
		Collections.sort(list, new Comparator<Student>() 
			@Override
			public int compare(Student stu1, Student stu2) 
				return stu1.getAge() - stu2.getAge();
			
		);
		System.out.println(list);
	

打印结果:


拓展:

        根据 JAVA8 的 lambda 表达式上面Compartor比较器的代码可以简写成以下代码:

		Collections.sort(list, (stu11, stu21) -> stu11.getAge() - stu21.getAge());

        再进一步简化成如下代码:

    Collections.sort(list, Comparator.comparingInt(Student::getAge));
或
    Collections.sort(list, Comparator.comparing(Student::getAge));

通过查询 comparing开头的方法,可以看见:

经过我的测试发现comparing兼容了下面三种基于整型数据的方法:

显然用comparing很省事,但是一般兼容性越高,效率也就越低,可以推测出comparing方法内部肯定是有一重判断了参数的数据类型的逻辑,这会降低代码执行效率;因此,如果是整型数据的话,建议使用上面三种与数据类型对应的方法,而如果是字符串的话,就使用comparing。

简化后:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class TestUtil 
	public static void main(String[] args) 
		Student stu1 = new Student("小米", 1);
		Student stu2 = new Student("小王", 2);
		Student stu3 = new Student("小明", 3);

		List<Student> list = new ArrayList<>();
		list.add(stu2);
		list.add(stu1);
		list.add(stu3);

		System.out.println("排序前:");
		System.out.println(list);

		System.out.println("排序后:");
		Collections.sort(list, Comparator.comparingInt(Student::getAge));
		System.out.println(list);
	

打印结果:

可以看出这是升序排序的,那么如何降序呢?

由于降序=升序的倒序,所以可以使用倒序的方法【.reversed()】实现降序:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class TestUtil 
	public static void main(String[] args) 
		Student stu1 = new Student("小米", 1);
		Student stu2 = new Student("小王", 2);
		Student stu3 = new Student("小明", 3);

		List<Student> list = new ArrayList<>();
		list.add(stu2);
		list.add(stu1);
		list.add(stu3);

		System.out.println("排序前:");
		System.out.println(list);

		System.out.println("排序后:");
		Collections.sort(list, Comparator.comparingInt(Student::getAge));
		System.out.println(list);
        System.out.println("倒序后:");
		Collections.sort(list, Comparator.comparingInt(Student::getAge).reversed());
		System.out.println(list);
	

打印结果:

多条件排序:

Student实体类:

@Data
@AllArgsConstructor
public class Student

	private String name;

	private int age;

	private double grade;

	private int tall;

测试:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class TestUtil 
	public static void main(String[] args) 
		Student stu1 = new Student("小米", 20, 95.0, 175);
		Student stu2 = new Student("小王", 20, 90.5, 175);
		Student stu3 = new Student("小明", 20, 90.0, 180);

		List<Student> list = new ArrayList<>();
		list.add(stu2);
		list.add(stu1);
		list.add(stu3);

		System.out.println("排序前:");
		System.out.println(list);
		System.out.println("排序后:");
		Collections.sort(list, Comparator.comparingInt(Student::getTall));
		System.out.println(list);
		System.out.println("倒序后:");
		Collections.sort(list, Comparator.comparingInt(Student::getTall).reversed());
		System.out.println(list);

		System.out.println("1.按年龄升序、分数升序、身高升序排序:");
		Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).thenComparingInt(Student::getTall));
		System.out.println(list);
		System.out.println("2.按年龄升序、分数升序、身高降序序排序:");
		Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).thenComparingInt(Student::getTall).reversed());
		System.out.println(list);
		System.out.println("3.按年龄升序、分数降序、身高升序排序:");
		Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).reversed().thenComparingInt(Student::getTall));
		System.out.println(list);
		System.out.println("4.按年龄升序、分数降序、身高降序序排序:");
		Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).reversed().thenComparingInt(Student::getTall).reversed());
		System.out.println(list);
		System.out.println("5.按年龄升序、身高升序、分数升序排序:");
		Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).thenComparingDouble(Student::getGrade));
		System.out.println(list);
		System.out.println("6.按年龄升序、身高升序、分数降序序排序:");
		Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).thenComparingDouble(Student::getGrade).reversed());
		System.out.println(list);
		System.out.println("7.按年龄升序、身高降序、分数升序排序:");
		Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).reversed().thenComparingDouble(Student::getGrade));
		System.out.println(list);
		System.out.println("8.按年龄升序、身高降序、分数降序序排序:");
		Collections.sort(list, Comparator.comparing(Student::getAge).thenComparing(Student::getGrade).reversed().thenComparing(Student::getTall).reversed());
		System.out.println(list);
	

打印结果:


3、list.stream().sorted()

JAVA8 之后,引入了stream流操作,可以极大提高集合的链式操作效率,关于stream流操作不太清楚的小伙伴,可以自行查阅资料,比较简单,这里就不再拓展了;

这里要提的是stream流操作中的 sorted()方法可以用于排序,其逻辑原理和上面第二种 Comparator 的排序方式是一样的。

这种方式与需要满足以下条件:
        1.1、list集合中元素的数据类型是一个java对象;

        1.2、引入stream流操作规范;

优点:排序算法效率高。

 Student实体类:

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Student

	private String name;

	private int age;

测试:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class TestUtil 
	public static void main(String[] args) 
		Student stu1 = new Student("小米", 1);
		Student stu2 = new Student("小王", 2);
		Student stu3 = new Student("小明", 3);

		List<Student> list = new ArrayList<>();
		list.add(stu2);
		list.add(stu1);
		list.add(stu3);

		System.out.println("排序前:");
		System.out.println(list);

		System.out.println("排序后:");
		list = list.stream().sorted(Comparator.comparing(Student::getAge)).collect(Collectors.toList());
		System.out.println(list);
	

打印结果:

同样的以使用倒序的方法【.reversed()】实现降序:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class TestUtil 
	public static void main(String[] args) 
		Student stu1 = new Student("小米", 1);
		Student stu2 = new Student("小王", 2);
		Student stu3 = new Student("小明", 3);

		List<Student> list = new ArrayList<>();
		list.add(stu2);
		list.add(stu1);
		list.add(stu3);

		System.out.println("排序前:");
		System.out.println(list);

		System.out.println("排序后:");
		list = list.stream().sorted(Comparator.comparing(Student::getAge)).collect(Collectors.toList());
		System.out.println(list);
		System.out.println("倒序后:");
		list = list.stream().sorted(Comparator.comparing(Student::getAge).reversed()).collect(Collectors.toList());
		System.out.println(list);
	

打印结果:


拓展:

        很多使用不仅需要对单一字段进行排序,还需要多个字段排序,因此多条件排序很重要!

多条件排序:

 Student实体类:

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Student

	private String name;

	private int age;

	private double grade;

	private int tall;

测试:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class TestUtil 
	public static void main(String[] args) 
		Student stu1 = new Student("小米", 20, 95.0, 175);
		Student stu2 = new Student("小王", 20, 90.5, 175);
		Student stu3 = new Student("小明", 20, 90.0, 180);

		List<Student> list = new ArrayList<>();
		list.add(stu2);
		list.add(stu1);
		list.add(stu3);

		System.out.println("排序前:");
		System.out.println(list);

		System.out.println("1.按年龄升序、分数升序、身高升序排序:");
		list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).thenComparingInt(Student::getTall)).collect(Collectors.toList());
		System.out.println(list);
		System.out.println("2.按年龄升序、分数升序、身高降序序排序:");
		list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).thenComparingInt(Student::getTall).reversed()).collect(Collectors.toList());
		System.out.println(list);
		System.out.println("3.按年龄升序、分数降序、身高升序排序:");
		list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).reversed().thenComparingInt(Student::getTall)).collect(Collectors.toList());
		System.out.println(list);
		System.out.println("4.按年龄升序、分数降序、身高降序序排序:");
		list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).reversed().thenComparingInt(Student::getTall).reversed()).collect(Collectors.toList());
		System.out.println(list);
		System.out.println("5.按年龄升序、身高升序、分数升序排序:");
		list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).thenComparingDouble(Student::getGrade)).collect(Collectors.toList());
		System.out.println(list);
		System.out.println("6.按年龄升序、身高升序、分数降序序排序:");
		list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).thenComparingDouble(Student::getGrade).reversed()).collect(Collectors.toList());
		System.out.println(list);
		System.out.println("7.按年龄升序、身高降序、分数升序排序:");
		list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).reversed().thenComparingDouble(Student::getGrade)).collect(Collectors.toList());
		System.out.println(list);
		System.out.println("8.按年龄升序、身高降序、分数降序序排序:");
		list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).reversed().thenComparingDouble(Student::getGrade).reversed()).collect(Collectors.toList());
		System.out.println(list);
	

打印结果:

​​​​​​​


总结:

        推荐使用第三种排序方法,因为stream流操作排序效率最高


4、List<JSONObject>排序

这个其实才是这篇文章的重点,很多时候为了方便,我们会用到JSONObject或者Map对象去接收数据库返回的结果集;

        1、例如当数据库表过多的时候,我们并不想为每个表都创建一个java实体类去接收数据;

        2、尤其是当我们想动态的查询出自己想要的数据,而结果中的字段名很可能并不是固定的;

        3、当然还有很多其他的复杂情况。。。

当我们使用的这一类不是由java实体类组成的List集合的时候,上面的那三种方法显然是未必适用的,于是为了应对这种情况下的排序需求,经过我的测试,总结出了下面3种情况和方法:

4.1、List<JSONObject>的单条件升序(默认)排序

大多数情况下,我们需要排序的时候,都是单条件排序,所以这是最基本的排序方法,基本上和第三种排序方式(list.stream().sorted())中的单条件排序的写法很类似,所以比较简单。

测试:

public class TestDemoUtil 
	public static void main(String[] args) 
		List<JSONObject> list = new ArrayList<>();
		JSONObject jsonObject1 = new JSONObject();
		JSONObject jsonObject2 = new JSONObject();
		JSONObject jsonObject3 = new JSONObject();

		jsonObject1.put("name", "小米");
		jsonObject1.put("age", 20);
		jsonObject1.put("grade", 95.0);
		jsonObject1.put("tail", 175);

		jsonObject2.put("name", "小王");
		jsonObject2.put("age", 20);
		jsonObject2.put("grade", 90.5);
		jsonObject2.put("tail", 175);

		jsonObject3.put("name", "小明");
		jsonObject3.put("age", 20);
		jsonObject3.put("grade", 90.0);
		jsonObject3.put("tail", 180);
		list.add(jsonObject1);
		list.add(jsonObject2);
		list.add(jsonObject3);

		System.out.println("排序前:");
		System.out.println(list);
		System.out.println("按成绩升序排序后:");
		list = list.stream().sorted(Comparator.comparingDouble(o -> o.getDoubleValue("grade"))).collect(Collectors.toList());
		System.out.println(list);
	

打印结果:

4.2、List<JSONObject>的单条件降序排序

        需要注意的是,和上面提到的第三种排序方式(list.stream().sorted())不同,在对集合进行降序排序的时候,无法直接在链式链式调用后面加上【.reversed()】来实现降序了;经过测试发现list.stream().sorted()对于JSONObject这一类非自定义的java对象无法完美是使用链式调用了,原因很可能是因为JSONObject这一类对象没有确定属性的getter/setter方法,所以下面这种写法会在编译的时候报错:

		list = list.stream().sorted(Comparator.comparingDouble(o -> o.getDoubleValue("grade")).reversed()).collect(Collectors.toList());

猜测原因应该是因为在链式调用中 getDoubleValue 会被识别为 JSONObject对象中 doubleValue属性对应的 getter方法,而该对象根本没有这个属性,所以就报错了,所以还是那句话链式调用的规则,并不适用于没有确定属性的这一类对象。

所以可以使用下面这种写法来解决降序的问题:

测试:

public class TestDemoUtil 
	public static void main(String[] args) 
		List<JSONObject> list = new ArrayList<>();
		JSONObject jsonObject1 = new JSONObject();
		JSONObject jsonObject2 = new JSONObject();
		JSONObject jsonObject3 = new JSONObject();

		jsonObject1.put("name", "小米");
		jsonObject1.put("age", 20);
		jsonObject1.put("grade", 95.0);
		jsonObject1.put("tail", 175);

		jsonObject2.put("name", "小王");
		jsonObject2.put("age", 20);
		jsonObject2.put("grade", 90.5);
		jsonObject2.put("tail", 175);

		jsonObject3.put("name", "小明");
		jsonObject3.put("age", 20);
		jsonObject3.put("grade", 90.0);
		jsonObject3.put("tail", 180);
		list.add(jsonObject1);
		list.add(jsonObject2);
		list.add(jsonObject3);

		System.out.println("排序前:");
		System.out.println(list);
		System.out.println("按成绩升序排序后:");
		list = list.stream().sorted(Comparator.comparingDouble(o -> o.getDoubleValue("grade"))).collect(Collectors.toList());
		System.out.println(list);
		System.out.println("按成绩降序排序后:");
		list = list.stream().sorted((o1, o2) -> o2.getDoubleValue("grade") - o1.getDoubleValue("grade") > 0 ? 1 : -1).collect(Collectors.toList());
		System.out.println(list);
	

打印结果:

 4.3、List<JSONObject>的多条件排序

多条件排序是重点,虽然很多时候我们只需要单条件排序;但多条件排序的写法才是重点,因为这种写法是最基础的,也是兼容最强的。

测试:

public class TestDemoUtil 
	public static void main(String[] args) 
		List<JSONObject> list = new ArrayList<>();
		JSONObject jsonObject1 = new JSONObject();
		JSONObject jsonObject2 = new JSONObject();
		JSONObject jsonObject3 = new JSONObject();

		jsonObject1.put("name", "小米");
		jsonObject1.put("age", 20);
		jsonObject1.put("grade", 95.0);
		jsonObject1.put("tail", 175);

		jsonObject2.put("name", "小王");
		jsonObject2.put("age", 20);
		jsonObject2.put("grade", 90.5);
		jsonObject2.put("tail", 175);

		jsonObject3.put("name", "小明");
		jsonObject3.put("age", 20);
		jsonObject3.put("grade", 90.0);
		jsonObject3.put("tail", 180);
		list.add(jsonObject1);
		list.add(jsonObject2);
		list.add(jsonObject3);

		System.out.println("排序前:");
		System.out.println(list);
		System.out.println("按成绩排序后:");
		list = list.stream().sorted(Comparator.comparingDouble(o -> o.getDoubleValue("grade"))).collect(Collectors.toList());
		System.out.println(list);

		System.out.println("1.按年龄升序、分数升序、身高升序排序:");
		list = list.stream().sorted((o1, o2) -> 
			int value = o1.getIntValue("age") - o2.getIntValue("age");
			if ( value == 0 ) 
				double v = o1.getDoubleValue("grade") - o2.getDoubleValue("grade");
				if ( v == 0.0 ) 
					return o1.getIntValue("tail") - o2.getIntValue("tail");
				
				return v > 0.0 ? 1 : -1;
			
			return value;
		).collect(Collectors.toList());
		System.out.println(list);

		System.out.println("2.按年龄升序、分数降序、身高升序排序:");
		list = list.stream().sorted((o1, o2) -> 
			int value = o1.getIntValue("age") - o2.getIntValue("age");
			if ( value == 0 ) 
				double v = o2.getDoubleValue("grade") - o1.getDoubleValue("grade");
				if ( v == 0.0 ) 
					return o1.getIntValue("tail") - o2.getIntValue("tail");
				
				return v > 0.0 ? 1 : -1;
			
			return value;
		).collect(Collectors.toList());
		System.out.println(list);

		System.out.println("3.按年龄升序、身高升序、分数降序排序:");
		list = list.stream().sorted((o1, o2) -> 
			int value = o1.getIntValue("age") - o2.getIntValue("age");
			if ( value == 0 ) 
				value = o1.getIntValue("tail") - o2.getIntValue("tail");
				if ( value == 0 ) 
					return o2.getDoubleValue("grade") - o1.getDoubleValue("grade") > 0.0 ? 1 : -1;
				
				return value;
			
			return value;
		).collect(Collectors.toList());
		System.out.println(list);
	

上面的代码可以通过提取公共方法,来提高代码复用率,由于和文章主题无关,这里就不进一步优化了。

打印结果:

 

JAVA集合类总结

【Java集合的详细研究】List,Set,Map用法以及区别

Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素。一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java JDK不能提供直接继承自Collection的类,Java JDK提供的类都是继承自Collection的"子接口",如:List和Set。 

注意:Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同key,每个key只能映射一个value。Map接口提供3种集合的视图,Map的内容可以被当做一组key集合,一组value集合,或者一组key-value映射。 


详细介绍: 
List特点:元素有放入顺序,元素可重复 
Map特点:元素按键值对存储,无放入顺序 
Set特点:元素无放入顺序,元素不可重复(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的) 
List接口有三个实现类:LinkedList,ArrayList,Vector 
LinkedList:底层基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储下一个元素的地址。链表增删快,查找慢 
ArrayList和Vector的区别:ArrayList是非线程安全的,效率高;Vector是基于线程安全的,效率低 
Set接口有两个实现类:HashSet(底层由HashMap实现),LinkedHashSet 
SortedSet接口有一个实现类:TreeSet(底层由平衡二叉树实现) 
Query接口有一个实现类:LinkList 
Map接口有三个实现类:HashMap,HashTable,LinkeHashMap 
  HashMap非线程安全,高效,支持null;HashTable线程安全,低效,不支持null 
SortedMap有一个实现类:TreeMap 
其实最主要的是,list是用来处理序列的,而set是用来处理集的。Map是知道的,存储的是键值对 
set 一般无序不重复.map kv 结构 list 有序

 

StringBuffer 线程安全,StringBuilder 线程不安全 效率稍高些
集(Set):集里的对象不按任何特定的方式排列,按索引值来操作数据,不能有重复的元素
列表(List):序列中的对象以线性方式存储,按索引值来操作数据,可以有重复的元素
映射(Map):映射的每一项为“名称—数值”对,名称不可以重复,值可以重复,一个名称对应一个唯一的值

显示指定集合类型:不经历装箱过程。
Collection<TaskVO> resulte = dao.retrieveByClause(TaskVO.class, sql);
转换为数组时,明确指定返回数组的大小
return result.toArray(new TaskVO[result.size()]);
数组不能强制转型:
String[] s= (String[])list.toArray();——错误
String[] s= (String[])list.toArray(new String[list.size()]);——正确

迭代器是按次序一个一个地获取集合中所有的对象,是访问集合中每个元素的标准机制。
迭代器的创建:Collection接口的iterator()方法返回一个Iterator
Iterator it=test.iterator(); //将test集合对象转为迭代器
迭代器的常用方法:
hasNext() //判断迭代器中是否有下一个元素
next() //返回迭代的下一个元素
Remove() //将迭代器新返回的元素删除

The Iterator interface is shown below: public interface Iterator {
boolean hasNext();
Object next();
void remove(); // Optional
}
可以认为迭代器是指向两个元素之间的位置.
在调用remove()方法的时候, 必须调用一次next()方法.
remove()方法实际上是删除上一个返回的元素.

List常用方法:
void add(int index, Object element) :添加对象element到位置index上
boolean addAll(int index, Collection collection) :在index位置后添加容器collection中所有的元素
Object get(int index) :取出下标为index的位置的元素
int indexOf(Object element) :查找对象element 在List中第一次出现的位置
int lastIndexOf(Object element) :查找对象element 在List中最后出现的位置
Object remove(int index) :删除index位置上的元素
ListIterator listIterator(int startIndex) :返回一个ListIterator 跌代器,开始位置为startIndex
List subList(int fromIndex, int toIndex) :返回一个子列表List ,元素存放为从 fromIndex 到toIndex之前的一个元素


ArrayList:我们可以将其看作是能够自动增长容量的数组。
利用ArrayList的toArray()返回一个数组。
Arrays.asList()返回一个列表。
迭代器(Iterator) 给我们提供了一种通用的方式来访问集合中的元素。


View方式:
一种是测量迭代元素的时间:
另一种测量使用toArray调用创建数组:
最后得到结果:
使用toArray调用中创建的数组迭代元素的速度要比使用iterator的速度大约快30%到60%。
但如果将使用toArray方法创建数组的时间开销含在内。则使用iterator实际上要快10%到20%,所以我们尽量不要创建中间数组。而使用迭代的方式。

ArrayList自动扩充机制
实现机制:ArrayList.ensureCapacity(int minCapacity)
首先得到当前elementData 属性的长度oldCapacity。
然后通过判断oldCapacity和minCapacity参数谁大来决定是否需要扩容, 如果minCapacity大于
oldCapacity,那么我们就对当前的List对象进行扩容。
扩容的的策略为:取(oldCapacity * 3)/2 + 1和minCapacity之间更大的那个。然后使用数组拷
贝的方法,把以前存放的数据转移到新的数组对象中
如果minCapacity不大于oldCapacity那么就不进行扩容。

LinkedList
LinkedList是采用双向循环链表实现的。
利用LinkedList实现栈(stack)、队列(queue)、双向队列(double-ended queue )。
它具有方法addFirst()、addLast()、getFirst()、getLast()、removeFirst()、removeLast()等。

用LinkedList实现队列:
队列(Queue)是限定所有的插入只能在表的一端进行,而所有的删除都在表的另一端进行的线性表。
表中允许插入的一端称为队尾(Rear),允许删除的一端称为队头(Front)。
队列的操作是按先进先出(FIFO)的原则进行的。
队列的物理存储可以用顺序存储结构,也可以用链式存储结构。

用LinkedList实现栈:
栈(Stack)也是一种特殊的线性表,是一种后进先出(LIFO)的结构。
栈是限定仅在表尾进行插入和删除运算的线性表,表尾称为栈顶(top),表头称为栈底(bottom)。
栈的物理存储可以用顺序存储结构,也可以用链式存储结构。

ArrayList和LinkedList的比较:
ArrayList底层采用数组完成,而LinkedList则是以一般的双向链表(double-linked list)完成,其内每个对象除了数据本身外,还有两个 引用,分别指向前一个元素和后一个元素。
如果我们经常在List的开始处增加元素,或者在List中进行插入和删除操作,我们应该使用LinkedList,否则的话,使用ArrayList将更加快速。

小结:
集合是一个保存其他对象的对象
Collection接口除了实现映射的集合类之外的所有集合类定义了一些方法
List集合类型描述了一种按位置存储数据的对象,有序的。
ArrayList是一种在内存连续区域 中存储数据的通用数组

编码习惯:
面向接口的编程,尽可能降低代码变化率:
List<T> lst = new ArrayList<T>();
尽量避免创建不必要的对象:vo应在if判断成立时创建
TaskReportVO reportvos = new TaskReportVO();
if(i > 0){
lstAllVos.add(reportvos); }
尽量避免同时遍历和删除集合。因为这会改变集合的大小;
for( Iterator<ComType> iter = ComList.iterator(); iter.hasNext();){
ComType com = iter.next();
if ( !com.getName().contains("abc")){
ComList.remove(com);}
}

推荐:
for( Iterator<ComType> iter = ComList.iterator(); iter.hasNext();){
ComType com = iter.next();
if ( !com.getName().contains("abc")){
iter.remove(com); }

预估集合内持有对象的大小,不能持有大量对象,占据内存:
List<T> lst = new ArrayList<T>();
无限制的在lst中add element,势必会造成lst占用内存过高。造成内存溢出

Map接口:
集合框架的第二类接口树。
它提供了一组键值的映射。其中存储的每个对象都有一个相应的关键字(key),关键字决定了对象在Map中的存储位置。
关键字应该是唯一的,每个key 只能映射一个value。
常用方法:
Object put(Object key,Object value):用来存放一个键-值对Map中
Object remove(Object key):根据key(键),移除键-值对,并将值返回
void putAll(Map mapping) :将另外一个Map中的元素存入当前的Map中
void clear() :清空当前Map中的元素
Object get(Object key) :根据key(键)取得对应的值
boolean containsKey(Object key) :判断Map中是否存在某键(key)
boolean containsValue(Object value):判断Map中是否存在某值(value)
public Set keySet() :返回所有的键(key),并使用Set容器存放
public Collection values() :返回所有的值(Value),并使用Collection存放
public Set entrySet() :返回一个实现 Map.Entry 接口的元素 Set

HashMap:
Map 主要用于存储键(key)值(value)对,根据键得到值,因此键不允许重复,但允许值重复。
HashMap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。
HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null;
HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力。

HashMap实现原理---散列
Hash哈希算法的意义在于提供了一种快速存取数据的方法,它用一种算法建立键值与真实值之间的对应关系。散列表又称为哈希表。散列表算法的基本思想是:以结点的关键字为自变量,通过一定的函数关系(散列函数)计算出对应的函数值,以这个值作为该结点存储在散列表中地址。
当散列表中的元素存放太满,就必须进行再散列,将产生一个新的散列表,所有元素存放到新的散列表中,原先的散列表将被删除。在Java语言中,通过负载因子(load factor)来决定何时对散列表进行再散列。例如:如果负载因子0.75,当散列表中已经有75%位置已经放满,那么将进行再散列。
负载因子越高(越接近1.0),内存的使用效率越高,元素的寻找时间越长。负载因子越低(越接近0.0),元素的寻找时间越短,内存浪费越多。

何时需重写equals?
当一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念);
Object类仅仅提供了一个对引用的比较,如果两个引用不是同一个那就返回false,这是无法满足大多数对象比较的需要的,所以要覆盖;
使用==操作符检查实参是否为指向对象的引用”
使用instanceof操作符检查实参是否为正确的类型
把实参转换到正确的类型;
对于该类中每一个“关键”域,检查实参中的域与当前对象中对应的域值是否匹 配。对于既不是float也不是double类型的基本类型的域,可以使用==操作符 进行比较;对于对象引用类型的域,可以递归地调用所引用的对象的equals方法,对于float和double类型的域,先转换成int或long类型的值,然后使用==操作符比较;
当你编写完成了equals方法之后,应该问自己三个问题:它是否是对称的、传 递的、一致的? 如果答案是否定的,那么请找到 这些特性未能满足的原因,再修改equals方法的代码

equals()和hashCode()同时覆写
尤其强调当一个对象被当作键值(或索引)来使用的时候要重写这两个方法;
覆写equals后,两个不同实例可能在逻辑上相等,但是根据Object.hashCode方法却产生不同的散列码,违反“相等的对象必须具有相等的散列码”。
导致,当你用其中的一个作为键保存到hashMap、hasoTable或hashSet中,再以“相等的”找另 一个作为键值去查找他们的时候,则根本找不到
不同类型的hashCode取值
如果该域是布尔型的,计算(f?0:1)
如果是char,short,byte或int,计算(int)f
如果是long类型,计算(int)(f^(f>>>32))
如果是float类型,计算Float.floatToIntBits(f)
如果是double类型,计算Dobule.doubleToLongBits(f)
如果该域是一个对象引用,递归调用hashCode
如果该域是一个数组,则把每个元素当做单独的域来处理,对每个重要的元素计算一个散列码,
比较:
HashMap的存入顺序和输出顺序无关。
LinkedHashMap 则保留了键值对的存入顺序。
TreeMap则是对Map中的元素进行排序。
因为HashMap和LinkedHashMap 存储数据的速度比直接使用TreeMap 要快,存取效率要高。
当完成了所有的元素的存放后,我们再对整个的Map中的元素进行排序。这样可以提高整个程序的运行的效率,缩短执行时间。
注意:TreeMap中是根据键(Key)进行排序的。而如果我们要使用TreeMap来进行正常的排序的话,Key 中存放的对象必须实现Comparable 接口。

Set:
扩展Collection接口
不允许重复元素
对 add()、equals() 和 hashCode() 方法添加了限制
HashSet和TreeSet是Set的实现
Set—》hashSet linkedHashSet
SortedSet —》 TreeSet

HashSet常用方法:
public boolean contains(Object o) :如果set包含指定元素,返回true
public Iterator iterator()返回set中元素的迭代器
public Object[] toArray() :返回包含set中所有元素的数组public Object[] toArray(Object[] a) :返回包含set中所有元素的数组,返回数组的运行时类型是指定数组的运行时类型
public boolean add(Object o) :如果set中不存在指定元素,则向set加入
public boolean remove(Object o) :如果set中存在指定元素,则从set中删除
public boolean removeAll(Collection c) :如果set包含指定集合,则从set中删除指定集合的所有元素
public boolean containsAll(Collection c) :如果set包含指定集合的所有元素,返回true。如果指定集合也是一个set,只有是当前set的子集时,方法返回true

实现Set接口的HashSet,依靠HashMap来实现的。
我们应该为要存放到散列表的各个对象定义hashCode()和equals()。
如何达到不能存在重复元素的目的?
“键”就是我们要存入的对象,“值”则是一个常量。这样可以确保,我们所需要的存储的信息
之是“键”。而“键”在Map中是不能重复的,这就保证了我们存入Set中的所有的元素都不重复。
HashSet如何过滤重复元素
调用元素HashCode获得哈希码--》判断哈希码是否相等,不相等则录入
---》相等则判断equals()后是否相等,不相等在进行 hashcode录入,相等不录入

TreeSet:
TreeSet是依靠TreeMap来实现的。
TreeSet是一个有序集合,TreeSet中元素将按照升序排列,缺省是按照自然顺序进行排列,意味着TreeSet中元素要实现Comparable接口
我们可以在构造TreeSet对象时,传递实现了Comparator接口的比较器对象。

几种Set的比较:
HashSet外部无序地遍历成员。
成员可为任意Object子类的对象,但如果覆盖了equals方法,同
时注意修改hashCode方法。
TreeSet外部有序地遍历成员;
附加实现了SortedSet, 支持子集等要求顺序的操作
成员要求实现Comparable接口,或者使用Comparator构造
TreeSet。成员一般为同一类型。
LinkedHashSet外部按成员的插入顺序遍历成员
成员与HashSet成员类似
HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。

HashSet的元素存放顺序和我们添加进去时候的顺序没有任何关系,而LinkedHashSet 则保持元素的添加顺序。TreeSet则是对我们的Set中的元素进行排序存放。

一般来说,当您要从集合中以有序的方式抽取元素时,TreeSet 实现就会有用处。为了能顺利进行,添加到 TreeSet 的元素必须是可排序的。 而您同样需要对添加到TreeSet中的类对象实现 Comparable 接口的支持。一般说来,先把元素添加到 HashSet,再把集合转换为 TreeSet 来进行有序遍历会更快。

Comparable和Comparator
Comparable 接口以提供自然排序顺序。
对于那些没有自然顺序的类、或者当您想要一个不同于自然顺序的顺序时,您可以实现
Comparator 接口来定义您自己的排序函数。可以将Comparator传递给Collections.sort或Arrays.sort。

Comparator接口
当一个类并未实现Comparable,或者不喜欢缺省的Comaparable行为。可以实现Comparator接口
直接实现Comparator的compare接口完成自定义比较类。
例:Arrays.sort(results, new Comparator<RepDataQueryResultVO>() 数组排序 RepDataQueryExecutor
例:Collections.sort(lst,new Comparator<TaskPrintSchemeVO>()















































































































































































































































以上是关于List集合排序总结的主要内容,如果未能解决你的问题,请参考以下文章

JAVA集合类总结

阿里JAVA开发面试常问问题总结3

Java相关面试题总结+答案

Java Review (三十集合----- 操作集合的工具类: Collections)

Java Review (三十集合----- 操作集合的工具类: Collections)

java中两个list集合如何排序