(一)ArrayList类介绍
ArrayList是一个基于数组上的链表,但是不同的是ArrayList不是同步的。所以在性能上要比Vector好一些,但是当运行到多线程环境中时,可需要自己在管理线程的同步问题。
1.1:语法
ArrayList()
构造一个初始容量为 10 的空列表(每次递增容量的一半)
ArrayList(Collection<? extends E> c)
构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的
ArrayList(int initialCapacity)
构造一个具有指定初始容量的空列表
1.2:特殊方法
void ensureCapacity(int minCapacity)
如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数。
返回此列表中最后一次出现的指定元素的索引,或如果此列表不包含索引,则返回 -1。
protected void removeRange(int fromIndex, int toIndex)
移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。
1.3:遍历
package com.itlwc;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("lwc");
list.add("nxj");
// 遍历方法一
Iterator<String> ite1 = list.iterator();
while (ite1.hasNext()) {
String str = ite1.next();
System.out.println(str);
}
System.out.println("---------------------");
// 遍历方法二(方法一的变形)
for (Iterator<String> ite2 = list.iterator(); ite2.hasNext();) {
String str = ite2.next();
System.out.println(str);
}
System.out.println("---------------------");
// 遍历方法三
for(String s : list){
System.out.println(s);
}
}
}
/*
打印结果:
lwc
nxj
---------------------
lwc
nxj
---------------------
lwc
nxj
*/
1.4:总结
(1)ArrayList依赖于数组实现的,初始长度为10的Object[],并且可随需要而增加的动态数组当元素超过10,那么ArrayList底层会新生成一个数组,长度为原来的1.5倍+1,然后将原数组内容复制到新数组中,并且后续增加的内容会放到新数组中,当新数组无法容纳增加的元素,重复该过程。
(2)ArrayList对随机访问性能很好,但进行大量插入,删除操作,性能很差,因为操作之后后续元素需要移动。
1.5:实例
public class ArrayListReview {
public static void main(String[] args) {
ArrayList<Info> infosList=new ArrayList<>();
infosList.add(new Info(0, "aaa"));
infosList.add(new Info(1, "bbb"));
infosList.add(new Info(2, "ccc"));
infosList.add(new Info(3, "ddd"));
infosList.add(1, new Info(4, "eee")); // 按索引插入到指定位置
// foreach遍历输出
for (Info info : infosList) {
System.out.println(info);
}
System.out.println("------------------------");
// 截取字串
List<Info> subList = infosList.subList(1, 3);
subList.add(new Info(30, "fly"));
printList(subList);
ArrayList<Info> newInfosList=new ArrayList<>();
newInfosList.add(new Info(11, "qqq"));
newInfosList.add(new Info(12, "www"));
ArrayList<String> ss=new ArrayList<>();
// infosList.addAll(newInfosList); // 添加一个指定集合到原集合最后,注意两个集合的泛型参数一致
infosList.addAll(2,newInfosList); // 将指定集合插入到指定位置
//printList(infosList);
Info info = infosList.get(2); // 取出指定位置的元素
System.out.println(info);
infosList.set(0, new Info(10, "rrr")); // 替换指定索引位置的元素
//printList(infosList);
int index = infosList.indexOf(info); //根据元素获取元素第一次出现的索引,不存在则返回-1
int lastIndex = infosList.lastIndexOf(info); // 取出元素的最后一个匹配项的索引
int indexOf = infosList.indexOf(new Info(4,"eee")); // 重写了Info类的hashCode与equals方法,用于判断两个对象是否相同
System.out.println("index="+indexOf);
//printList(infosList);
// 通过反射拿到的removeRange方法
removeRange(infosList, 1, 3);
//printList(infosList);
// listIterator从前往后迭代
ListIterator<Info> listIterator = infosList.listIterator();
while(listIterator.hasNext()){
// 最后抛出错误,java.util.NoSuchElementException,不要每次取都掉用next方法,它每调用一次,迭代器指针向前移动一位
// System.out.println("id="+listIterator.next().getId()
// +"adress="+listIterator.next().getAdress());
Info next = listIterator.next(); // 正确做法,调用一次要取出元素,然后操作属性
System.out.println("id="+next.getId()
+" adress="+next.getAdress());
}
// 往前迭代,必须在往后迭代之后用
while(listIterator.hasPrevious()){ // 当有上一个元素时
Info previous = listIterator.previous(); // 获取上一个元素
System.out.println("id="+previous.getId()+" adresss="+previous.getAdress());
}
// 通过数组来转化成一个List,虽然可以把数组转成集合,但是集合的长度不能改变。
String[] a=new String[]{"hello","world","just","do","it"};
List<String> asList = Arrays.asList(a);
//asList.add("gogogo"); //不可修改asList,会抛出UnsupportedOperationException
// 泛型使用
// ArrayList<Object> l=new ArrayList<String>();// 不行
// ArrayList<ArrayList> lll=new ArrayList<List>(); // 不行
// ArrayList<List> lll=new ArrayList<ArrayList>(); // 不行
// ArrayList l=new ArrayList<String>(); // 可行
// ArrayList<String> l=new ArrayList<>(); // 可行
// ArrayList ll=new ArrayList(); // 可行
}
// 打印输出
public static <E> void printList(List<E> list) {
for (E e : list) {
System.out.println(e);
}
System.out.println("------------------------");
}
}
(二)ArrayList遍历的3种方法
2.1:Iterator方法遍历
for(Iterator it2 = list.iterator();it2.hasNext();){
System.out.println(it2.next());
}
2.2:for 第一种循环方式遍历
for(int i = 0;i < list.size(); i ++){
System.out.println(list.get(i));
}
2.3:for 第二种循环方式遍历
for(String tmp:list){
System.out.println(tmp);
}
2.4:实例
public class ListTest {
public static void main(String[] args)
{
List<String> list = new ArrayList<String>();
long start = 0L;
long end = 0L;
for(int j = 0; j < 1000000; j++)
{
list.add("aaaaaa" + j);
}
start = System.currentTimeMillis();
for(String tmp:list)
{
}
end = System.currentTimeMillis();
System.out.print("第一种方法运行时间:" + (end - start) + "(毫秒)\n");
start = System.currentTimeMillis();
for(int i = 0; i < list.size(); i++)
{
list.get(i);
}
end = System.currentTimeMillis();
System.out.print("第二种方法运行时间:" + (end - start) + "(毫秒)\n");
Iterator<String> iter = list.iterator();
start = System.currentTimeMillis();
while(iter.hasNext())
{
iter.next();
}
end = System.currentTimeMillis();
System.out.print("第三种方法运行时间:" + (end - start) + "(毫秒)\n");
}
}
执行的结果:
第一种方法运行时间:14(毫秒)
第二种方法运行时间:4(毫秒)
第三种方法运行时间:5(毫秒)
2.5:总结
1、方式1,3看着比较简洁,但是性能较差,这种方式在循环的过程中,会进行数据锁定,性能较差。
2、第二种方式,循环过程中数据不锁定,效率高,但是多线程的时候需要考虑并发操作的问题.
3、第一种方式比第三钟方式还要多一些处理,所以时间更久。
因此推荐用第二种
(三)ArrayList删除特定不同元素(2种)
3.1:使用下标的方式删除
在代码中,删除元素后,需要把下标减一。这是因为在每次删除元素后,ArrayList会将后面部分的元素依次往上挪一个位置(就是copy),所以,下一个需要访问的下标还是当前下标,所以必须得减一才能把所有元素都遍历完。
ArrayList al = new ArrayList();
al.add("a");
al.add("b");
al.add("b");
al.add("c");
for (int i = 0; i < al.size(); i++) {
if (al.get(i) == "b") {
al.remove(i);
i--;//一定要移动下标,不然会报错
}
}
3.2:使用Iterator元素遍历的方式删除
两种方案实现原理都差多的,性能也差别不大,第二种只是jdk封装了下。
Iterator<String> sListIterator = list.iterator();
while(sListIterator.hasNext()){
String e = sListIterator.next();
if(e.equals("3")){
sListIterator.remove();
}
}
(四)ArrayList删除重复元素(2种)
4.1:使用HashSet删除ArrayList中重复的元素
public static void main(String[] args)
{
//Constructing An ArrayList
ArrayList<String> listWithDuplicateElements = new ArrayList<String>();
listWithDuplicateElements.add("JAVA");
listWithDuplicateElements.add("J2EE");
listWithDuplicateElements.add("JSP");
listWithDuplicateElements.add("SERVLETS");
listWithDuplicateElements.add("JAVA");
listWithDuplicateElements.add("STRUTS");
listWithDuplicateElements.add("JSP");
//Printing listWithDuplicateElements
System.out.print("ArrayList With Duplicate Elements :");
System.out.println(listWithDuplicateElements);
//Constructing HashSet using listWithDuplicateElements
HashSet<String> set = new HashSet<String>(listWithDuplicateElements);
//Constructing listWithoutDuplicateElements using set
ArrayList<String> listWithoutDuplicateElements = new ArrayList<String>(set);
//Printing listWithoutDuplicateElements
System.out.print("ArrayList After Removing Duplicate Elements :");
System.out.println(listWithoutDuplicateElements);
}
输出:
注意输出结果。你会发现,在删除重复元素之后,元素重新洗牌。不再按照插入顺序排列。如果你想在删除重复的元素之后依然保持元素的插入顺序,那么不 建议使用此方法。还有另一种方法,可以保证在删除重复的元素之后也不改变元素的插入顺序。那就是使用LinkedHashSet。
ArrayList With Duplicate Elements :[JAVA, J2EE, JSP, SERVLETS, JAVA, STRUTS, JSP]
ArrayList After Removing Duplicate Elements :[JAVA, SERVLETS, JSP, J2EE, STRUTS]
4.2:使用LinkedHashSet删除ArrayList中重复的元素
public static void main(String[] args)
{
//Constructing An ArrayList
ArrayList<String> listWithDuplicateElements = new ArrayList<String>();
listWithDuplicateElements.add("JAVA");
listWithDuplicateElements.add("J2EE");
listWithDuplicateElements.add("JSP");
listWithDuplicateElements.add("SERVLETS");
listWithDuplicateElements.add("JAVA");
listWithDuplicateElements.add("STRUTS");
listWithDuplicateElements.add("JSP");
//Printing listWithDuplicateElements
System.out.print("ArrayList With Duplicate Elements :");
System.out.println(listWithDuplicateElements);
//Constructing LinkedHashSet using listWithDuplicateElements
LinkedHashSet<String> set = new LinkedHashSet<String>(listWithDuplicateElements);
//Constructing listWithoutDuplicateElements using set
ArrayList<String> listWithoutDuplicateElements = new ArrayList<String>(set);
//Printing listWithoutDuplicateElements
System.out.print("ArrayList After Removing Duplicate Elements :");
System.out.println(listWithoutDuplicateElements);
}
输出:
注意输出。你可以发现在删除ArrayList中的重复元素后,依然保持了元素的插入顺序。
ArrayList With Duplicate Elements :[JAVA, J2EE, JSP, SERVLETS, JAVA, STRUTS, JSP]
ArrayList After Removing Duplicate Elements :[JAVA, J2EE, JSP, SERVLETS, STRUTS]
(五)ArrayList合并并删除重复数据(3种)
5.1:通过List自带方法list.retainAll()
List temp=new ArrayList(l1);//用来保存两者共同有的数据
temp.retainAll(l2);//temp中只保留两者共同的数据
l1.removeAll(temp);//l1中去掉两者共同有的数据
List l3=new ArrayList();
l3.addAll(l1);
l3.addAll(l2);
System.out.println(l3);
5.2:构造Set集合。Set集合本身是不允许重复记录的
Set s=new TreeSet(l1);
for(Integer i:l2){
//当添加不成功的时候 说明s中已经存在该对象
s.add(i);
}
System.out.println(s);
5.3:遍历列表,对比数据
public static ArrayList addArrayList(ArrayList list1, ArrayList list2) {
ArrayList list3 = new ArrayList();
if (list1 == null || list1.size() == 0) {
list3 = list2;
} else if (list2 == null || list2.size() == 0) {
list3 = list1;
} else {
for (int i = 0; i < list1.size(); i++) { // 遍历list1
boolean isExist = false;
for (int j = 0; j < list2.size(); j++) {
if (list1.get(i).equals(list2.get(j))) {
isExist = true; // 找到相同项,跳出本层循环
break;
}
}
if (!isExist) { // 不相同,加入list3中
list3.add(list1.get(i));
}
}
for (int k = 0; k < list2.size(); k++) {
list3.add(list2.get(k));
}
}
return list3;
}
(六)ArrayList排序的3种方法
6.1:使用Collections.sort()方法进行排序
(1)ArrayList 存储着以字符串形式存在的国名(country name),为了对这个 ArrayList 进行排序,你需要调用 Collections.sort()方法。
(2)这种方法将按照自然顺序(按字母升序)对元素(国名)进行排序。代码如下:
public class SortArrayListAscendingDescending {
private ArrayList arrayList;
public SortArrayListAscendingDescending(ArrayList arrayList) {
this.arrayList = arrayList;
}
public ArrayList getArrayList() {
return this.arrayList;
}
public ArrayList sortAscending() {
Collections.sort(this.arrayList);
return this.arrayList;
}
public ArrayList sortDescending() {
Collections.sort(this.arrayList, Collections.reverseOrder());
return this.arrayList;
}
}
(3)在SortArrayListAscendingDescending类中,我们在构造器中初始化了一个 ArrayList 对象。在 sortAscending()方法中,我们调用了 Collections.sort()方法,并传递这个初始化的 ArrayList对象为参数,返回排序后的 ArrayList。
(4)在 sortDescending()方法中,我们调用重载的 Collections.sort()方法让其按照降序对元素排序,这个版本的 Collections.sort()接收ArrayList对象作为第一个参数,一个由 Collections.reverseOrder()方法返回的 Comparator 对象作为第二个参数。
public class SortArrayListAscendingDescendingTest {
public void testSortAscendingDescending() throws Exception {
ArrayList countryList = new ArrayList();
countryList.add("France");
countryList.add("USA");
countryList.add("India");
countryList.add("Spain");
countryList.add("England");
SortArrayListAscendingDescending sortArrayList = new SortArrayListAscendingDescending(countryList);
ArrayList unsortedArrayList = sortArrayList.getArrayList();
System.out.println("Unsorted ArrayList: " + unsortedArrayList);
ArrayList sortedArrayListAscending = sortArrayList.sortAscending();
System.out.println("Sorted ArrayList in Ascending Order : " +
sortedArrayListAscending);
ArrayList sortedArrayListDescending = sortArrayList.sortDescending();
System.out.println("Sorted ArrayList in Descending Order: " +
sortedArrayListDescending);
}
}
(5)在SortArrayListAscendingDescendingTest测试代码中,我们创建一个 ArrayList 对象,并添加了 5 个字符串对象代表 5 个国家的名字。然后我们调用 getArrayList()、sortAscending()和 sortDescending()方法,并打印这些方法返回的 ArrayList 对象。
显示结果:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running guru.springframework.blog.sortarraylist.ascendingdescending.SortArrayListAscendingDescendingTest
Unsorted ArrayList: [France, USA, India, Spain, England]
Sorted ArrayList in Ascending Order : [England, France, India, Spain, USA]
Sorted ArrayList in Descending Order: [USA, Spain, India, France, England]
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec - in guru.springframework.blog.sortarraylis
6.2:使用Comparable排序
(1)让我们来举一个例子,JobCandidate 类的对象保存在 ArrayList 中并准备对其进行排序。
(2)JobCandidate 类有三个成员变量:字符串类型的姓名和性别、整型的年龄。我们想要对保存在 ArrayList 中的 JobCandidate 对象按照年龄进行排序。因此我们要让 JobCandidate 类实现 Comparable 接口并重写 compareTo()方法。
public class JobCandidate implements Comparable {
private String name;
private String gender;
private int age;
public JobCandidate(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public String getName() {
return name;
}
public String getGender() {
return gender;
}
public int getAge() {
return age;
}
@Override
public int compareTo(JobCandidate candidate) {
return ((this.getAge() < candidate.getAge()) ? (-1)
: ((this.getAge() == candidate.getAge())
? 0 : 1));
}
@Override
public String toString() {
return " Name: " + this.name + ", Gender: " + this.gender + ", age:" +
this.age;
}
}
(3)JobCandidate 类被重写的 compareTo()方法中,我们实现了基于年龄的比较逻辑。
public class JobCandidateSorter {
ArrayList jobCandidate = new ArrayList<>();
public JobCandidateSorter(ArrayList jobCandidate) {
this.jobCandidate = jobCandidate;
}
public ArrayList getSortedJobCandidateByAge() {
Collections.sort(jobCandidate);
return jobCandidate;
}
}
(4)在 JobCandidateSorter 类中,我们初始化了一个 ArrayList 对象,委托方将通过构造函数实例化 JobCandidateSorter 。然后我们编写了 getSortedJobCandidateByAge()方法,在这个方法中,我们调用 Collections.sort()并传递已经初始化了的 ArrayList 为参数,最后返回排序后的 ArrayList。
public class JobCandidateSorterTest {
public void testGetSortedJobCandidateByAge() throws Exception {
JobCandidate jobCandidate1 = new JobCandidate("Mark Smith", "Male", 26);
JobCandidate jobCandidate2 = new JobCandidate("Sandy Hunt", "Female", 23);
JobCandidate jobCandidate3 = new JobCandidate("Betty Clark", "Female",
20);
JobCandidate jobCandidate4 = new JobCandidate("Andrew Styne", "Male", 24);
ArrayList jobCandidateList = new ArrayList();
jobCandidateList.add(jobCandidate1);
jobCandidateList.add(jobCandidate2);
jobCandidateList.add(jobCandidate3);
jobCandidateList.add(jobCandidate4);
JobCandidateSorter jobCandidateSorter = new JobCandidateSorter(jobCandidateList);
ArrayList sortedJobCandidate = jobCandidateSorter.getSortedJobCandidateByAge();
System.out.println("-----Sorted JobCandidate by age: Ascending-----");
for (JobCandidate jobCandidate : sortedJobCandidate) {
System.out.println(jobCandidate);
}
}
}
JobCandidateSorterTest类中,我们创建了四个 JobCandidate 对象并把它们添加到 ArrayList,然后传递这个 ArrayList 到构造函数来实例化 JobCandidateSorter 类。最后,我们调用 JobCandidateSorter 类的 getSortedJobCandidateByAge()方法,并打印这个方法返回的排序后的 ArrayList。
测试的输出结果如下:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running guru.springframework.blog.sortarraylist.comparable.JobCandidateSorterTest
-----Sorted JobCandidate by age: Ascending-----
Name: Betty Clark, Gender: Female, age:20
Name: Sandy Hunt, Gender: Female, age:23
Name: Andrew Styne, Gender: Male, age:24
Name: Mark Smith, Gender: Male, age:26
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.003 sec
- in guru.springframework.blog.sortarraylist.comparable.JobCandidateSorterTest
6.3:使用 Comparator 排序
比如我有一个Person类,它的实例对象存储在ArrayList数组中,现在要把ArrayList数组中的Person对象按照年龄排序.代码如下:
Person类
public class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Mycomparator类
public class Mycomparator implements Comparator {
public int compare(Object o1, Object o2) {
Person p1 = (Person) o1;
Person p2 = (Person) o2;
if (p1.age < p2.age) return 1;
else return 0;
}
}
ListSort类
当然,如果你的List包装的是基本类型或者String,则只要 Collections.sort(list);即可
public class ListSort {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add(new Person("lcl", 28));
list.add(new Person("fx", 23));
list.add(new Person("wqx", 29));
Comparator comp = new Mycomparator();
Collections.sort(list, comp);
for (int i = 0; i < list.size(); i) {
Person p = (Person) list.get(i);
System.out.println(p.getName());
}
}
}