精华内容
下载资源
问答
  • List集合

    千次阅读 2018-03-16 20:39:07
    List集合 1.List接口继承Collection接口,实现了List接口的类称为List集合。 2.在List集合中允许出现重复的元素,所有元素以线性方式进行存储,可以通过索引来访问集合中指定的元素。List集合的元素的存储顺序和...

    List集合

    1.List接口继承Collection接口,实现了List接口的类称为List集合。

    2.List集合中允许出现重复的元素,所有元素以线性方式进行存储,可以通过索引来访问集合中指定的元素。List集合的元素的存储顺序和取出顺序一致。

    3.List不但继承了Collection接口中的全部方法,还增加了一些根据元素位置索引来操作集合的特有方法。

    注意:集合不能定义为基本数据类型(int、char、float……),应该定义为包装类数据类型(Integer、String……)。

    ArrayList集合和LinkedList集合的区别:

    1、ArrayList集合底层是数组,而且是Object [] 类型;而LinkedList集合底层是链表。

    2、ArrayList集合查询数据很快,但是增删数据很慢;LinkedList集合增删数据很快。但是查询数据很慢。

    List集合中常用方法:

    add(Object object):向集合中添加数据

    get(int index):获取集合中指定的索引位置的元素数值

    size():获取集合的长度

    isEmpty():判断集合是否为空

    contains(Object object);//判断结合中是否含有指定的这个元素

    set(int index, Object object):更改集合中指定索引位置的元素数值

    toArray():将集合转换为数组

    remove(int index):删除集合中指定索引位置的元素数值

    clear():清空集合元素数值,谨慎使用

    ArrayList集合

    1.ArrayListList接口的一个实现类,它是程序中最常见的一种集合类;

    2.在ArrayList内部封装了一个数组对象,初始长度缺省为10,当存入的元素超过数组长度时,ArrayList会在内存中分配一个更大的数组来重新容纳这些元素,因此可以将ArrayList集合看作一个长度可变的数组;

    3.ArrayList集合类的大部分方法都是从父类CollectionList继承过来的,其中add()方法和get()方法用于实现元素的添加和读取。

    4.ArrayList集合的内部使用一个数组来保存元素。在删除元素时,会将被删除元素之后的元素都向前移一个位置以填补空位;而在用add(intindex, Object element)方法添加元素时,是把元素插入index指向的位置,先把该位置的元素以及后续元素都向后移一个位置,如果超出数组的容量,会创建更大的新数组。因为增删元素会导致大量的内存操作,所以效率低,但ArrayList集合允许通过索引随机的访问元素,查询效率高。

    5.集合和数组一样,索引的取值范围是从0开始,到size-1为止(size是集合的长度),不能超出此范围,否则会引发异常。add(Objecto)方法是把元素添加到集合的尾部,而add(intindex, Object o)是把元素添加到由索引index指定的位置。

    package com.test;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    
    public class Test1 {
    	
    	
    	@SuppressWarnings({ "unchecked", "rawtypes" })
    	public static void main(String[] args) {
    		
    		ArrayList alist = new ArrayList();
    		
    		//向集合alist中添加数据
    		alist.add(1);
    		alist.add(2);
    		alist.add(3);
    		alist.add(4);
    		alist.add(5.00);
    		alist.add(6.00);
    		alist.add("字符串1");
    		alist.add("字符串2");
    		alist.add('A');
    		alist.add('B');
    		
    		int length = alist.size();//获取集合的长度
    		System.out.println("集合长度是:"+length);//集合长度是:10
    		
    		boolean flag =  alist.isEmpty();//判断集合是否为空
    		boolean flag2 =  alist.contains(4);//判断结合中是否还有4这个数据
    		System.out.println("集合是否为空:"+flag);//集合是否为空:false
    		System.out.println("集合中是否含有数字4:"+flag2);//集合中是否含有数字4:true
    		
    		Object obj = alist.get(7);//获取集合下标为7的元素值
    		System.out.println("集合下标为7的元素值:"+obj);//集合下标为7的元素值:字符串2
    		
    		alist.set(4, "我是Hern");//更改集合下标为4的元素的值,将其修改为:我是Hern
    		
    		Object[] obj2 = alist.toArray();
    		System.out.println("数组obj2的数值是:");
    		for (Object object : obj2) {
    			System.out.println(object);
    		}//输出结果是:1  2  3  4  我是Hern  6.0  字符串1  字符串2  A  B
    		
    		
    		alist.remove(3);//删除集合下标为3的元素数值
    		
    		// alist.clear();//清空集合,谨慎使用
    		System.out.println("alist集合的数值是:");
    		for (Object object : alist) {
    			System.out.println(object);
    		}//输出结果是:1  2  3  我是Hern  6.0  字符串1  字符串2  A  B
    		
    	}
    
    }
    

    给ArrayList集合指定类型:

    package com.test;
    
    import java.lang.reflect.Array;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.LinkedList;
    
    public class Test1 {
    	
    	@SuppressWarnings({ "unchecked", "rawtypes" })
    	public static void main(String[] args) {
    		
    		ArrayList<String> alist = new ArrayList<>();
    		
    		//向集合alist中添加数据
    		alist.add("字符串1");
    		alist.add("字符串2");
    		alist.add("字符串3");
    		alist.add("字符串4");
    		alist.add("字符串5");
    		alist.add("字符串6");
    		
    		int length = alist.size();//获取集合的长度
    		System.out.println("集合长度是:"+length);//集合长度是:6
    		
    		boolean flag =  alist.isEmpty();//判断集合是否为空
    		boolean flag2 =  alist.contains(4);//判断结合中是否还有4这个数据
    		System.out.println("集合是否为空:"+flag);//集合是否为空:false
    		System.out.println("集合中是否含有数字4:"+flag2);//集合中是否含有数字4:false
    		
    		Object obj = alist.get(4);//获取集合下标为7的元素值
    		System.out.println("集合下标为4的元素值:"+obj);//集合下标为4的元素值:字符串5
    		
    		Object[] obj2 = alist.toArray();
    		
    		for(Object object : obj2) {
    			System.out.println(object);
    		}
    		
    		alist.remove(2);
    		alist.set(3, "我是Hern");
    		
    		System.out.println("alist集合的数值是:");
    		for (Object object : alist) {
    			System.out.println(object);
    		}//输出结果是:1  2  3  我是Hern  6.0  字符串1  字符串2  A  B
    		
    	}
    
    }
    

     

     LinkedList集合

    1.List接口的另一个实现类LinkedList,克服了ArrayList集合在增删元素时效率较低的局限性。但是LinkedList集合的查询效率低(不支持随机访问),要查询第n个元素,必须从第一个元素开始,逐一的向后遍历,直到第n个元素。

    2.该集合内部维护了一个双向链表,链表中的每个元素都通过对象引用来记住它的前一个元素和后一个元素,从而将所有的元素彼此连接起来。

    3.当插入一个新元素时,只需要修改元素之间的引用关系即可,删除一个节点也是如此。LinkedList集合添加元素和删除元素的过程如下图所示:

    ArrayList集合 和 LinkedList集合在进行插入的时候必须参照已有的顺序进行插入,如果插入到已存在的顺序中,将会把原有该位置的集合元素覆盖,如果插入的是在已有顺序之后的不连续位置则会运行的时候抛出异常。(例如已有的顺序为5,则不能向7中插入,可以向6中插入)。

    import java.util.*;
    import java.io.*;
    import java.math.*;
    
    public class Main{ 
        
    	public static void main(String[] args) {
    		LinkedList link = new LinkedList();   //创建LinkedList集合,初始为空列表
            link.add("stu1");
            link.add("stu2");
            link.add("stu3");
            link.add("stu4");
            
            System.out.println(link.get(2));	//获取下标位置为2的元素
            System.out.println(link.toString());  //打印集合中的元素
            
            link.add(3, "Student");   //向集合指定位置插入元素,会把原来3的位置元素替换掉
            link.addFirst("First");    //向集合第一个位置插入元素
            
            System.out.println(link);    //另一种方式打印集合中的元素
            
            System.out.println(link.getFirst());  //打印第一个元素
            
            link.remove(3);   //删除索引值为3的元素
            link.removeFirst();   //删除第一个元素
           
            System.out.println(link);  
    		/*运行结果是:
    		 stu3
    		 [stu1, stu2, stu3, stu4]
    		 [First, stu1, stu2, stu3, Student, stu4]
    		 First
    		 [stu1, stu2, Student, stu4]
    		*/
    	
    	}
    }

     

    展开全文
  • Java中List集合与Set集合

    千次阅读 2019-07-02 00:23:42
    一、List 集合 1、List 接口特点 2、List 接口中常用的方法 3、List 集合存储数据结构 4、ArrayList 集合ArrayList 集合是最常用的集合,是用存储数据结构,元素增删慢,查找快。 5、LinkedList 集合 6、...

    目录

    一、List 集合

    1、List 接口特点

    2、List 接口中常用的方法

    3、List 集合存储数据结构

    4、ArrayList 集合ArrayList 集合是最常用的集合,是用存储数据结构,元素增删慢,查找快。

    5、LinkedList 集合

    6、Vector 集合

    二、Set 接口

    1、HashSet 集合

    2、HashSet 集合存储数据的结构(哈希表)

    3、String 类的哈希值

    4、自定义对象重写hashCode和equals

    5、LinkedHashSet集合


    一、List 集合

    List 是一个接口,是有序的 collection,此接口的用户可以对列表中每个元素的插入位置进行精确的控制,用户可以根据元素的整数索引访问元素,并搜索列表中的元素。List 接口允许存放重复的元素,并且元素都是有序的(Set 接口不允许存放重复元素,元素是无序的)

    1、List 接口特点

    • 它是一个有序的集合
    • 他是一个带索引的集合,通过索引就可以精确地操作集合中的元素(与数组的索引是一个道理)
    • 集合中可以有重复的元素,可以通过 equals 方法来比较是否为重复的元素
    • List 接口常用的子类有:ArrayList 集合、LinkedList 集合

    2、List 接口中常用的方法

    • boolean add(Object e):向集合末尾添加指定元素
    • void add(int index,Object e):向集合指定索引处添加指定元素,原有元素依次后移
    • remove(Object e):将指定元素对象从集合中删除,返回被删除的元素
    • remove(int index):将指定索引处的元素从集合中删除,返回被删除的元素
    • set(int index,Object e):将指定索引处的元素替换成指定的元素,返回替换前的元素
    • get(int index):获取指定索引处的元素,返回该元素
    public static void main(String[] args)
    {
        List<String> L = new ArrayList<>();
        //末尾添加元素
        L.add("abc");
        L.add("bcd");
        L.add("cde");
        L.add("def");
        L.add("efg");
        //指定位置添加元素
        L.add(2,"fgh");
        //删除指定元素
        L.remove("abc");
        //删除指定索引元素
        L.remove(1);
        //将指定索引处的元素替换成指定元素
        L.set(1,"hello");
        //获取指定索引处的元素
        L.get(1);
        //使用迭代器获取出集合中的元素,最好使用listIterator进行迭代
        Iterator<String> it = L.listIterator();
        while(it.hasNext())
        {
            System.out.println(it.next());
        }
        //由于List集合是有索引的,还可以使用索引进行迭代
        for(int i = 0;i < L.size();i++)
        {
            System.out.println(L.get(i));
        }
    }

    注:

    • List 集合是带索引的有序集合,因此除了使用迭代器进行获取元素外,还可以使用索引下表进行元素获取
    • Iterator 迭代 List 异常问题:在迭代过程中,如果要添加一个新的元素,使用集合的方法对元素进行操作,会导致迭代器不知道集合中的变化,容易发生数据的不确定性。因此,通过 listIterator 迭代能避免这个异常。

    3、List 集合存储数据结构

    List 接口下有多个集合,它们存储元素所采用的数据结构方式有所不同,这就导致了不同集合有其不同特点,供程序员在不同的环境下使用。

    数据存储的常用结构有:堆栈、队列、数组、链表

    • 堆栈
      (1) 先进后出
      (2) 栈的入口、出口都是栈的顶端位置
      (3) 压栈:即存元素
      (4) 出栈:即取元素
    • 队列
      (1) 先进先出
      (2) 队列的入口、出口为两端
    • 数组
      (1) 查找元素快:通过索引快速访问指定元素位置
      (2) 增删元素慢:指定位置增加、删除元素都需要创建一个新的数组,将指定新元素存储在指定索引位置,再把原数组索引根据索引复制到新数组对应索引位置
    • 链表
      (1) 多个节点之间,通过地址进行连接
      (2) 查找元素慢:想要查找某个元素,需要通过连接的节点,依次向后查找指定元素
      (3) 增删元素快:只需修改连接下个元素的地址即可

    4、ArrayList 集合
    ArrayList 集合是最常用的集合,是用存储数据结构,元素增删慢,查找快。

    在我的另一篇博客:Java中ArrayList集合有其的介绍,这里不多说

    5、LinkedList 集合

    LinkedList 集合数据存储的结构是链表结构,对元素的增删很方便,实际开发中对一个集合元素的增删经常涉及到首位操作,而 LinkedList 集合提供了大量的首位操作方法。

    • void addFirst(E e):将指定元素插入链表的开头
    • void addLast(E e):将指定元素插入链表的结尾
    • E getFirst():返回链表的第一个元素
    • E getLast():返回链表的最后一个元素
    • E removeFirst():移除并返回链表的第一个元素
    • E removeLast():移除并返回链表的最后一个元素
    • E pop(E e):取出链表栈顶元素
    • void push(E e):将元素推入此链表所示的堆栈
    • boolean isEmpty():判断链表中是否有元素

    逻辑实例:

    public static void main(String[] args)
    {
        //创建链表
        LinkedList<String> link = new LinkedList<>();
        //添加元素
        link.add("abc");
        link.add("bcd");
        link.add("cde");
        link.add("def");
        //获取元素
        System.out.println(link.getFirst());
        System.out.println(link.getLast());
        //删除元素
        System.out.println(link.remove("abc"));
        System.out.println(link.removeFirst());
    
        while (link.isEmpty())  //判断集合是否有元素
        {
            System.out.println(link.pop());     //取出栈顶元素
        }
    }

    6、Vector 集合

    Vector 集合数据存储结构是数组结构,与 ArrayList 不同之处在于提供了一个独特的取出方法:枚举Enumeration,与 Iterator 接口功能类似。Vector 集合已被 ArrayList 集合替代,枚举Enumeration 已被迭代器 Iterator 替代(这里盗用一张图)

    二、Set 接口

    Set 集合里面存储的是无序的不重复元素,没有索引,可以采用迭代器和增强for来获取元素,Set 常用的子类有 HashSet、LinkedHashSet 集合,可以通过 equals 方法来判断是否为重复元素。

    1、HashSet 集合

    HashSet 类实现 Set 接口,由哈希表支持(实际上是一个 HashMap 集合),HashSet 集合不能保证迭代顺序与元素存储顺序相同,采用哈希表结构存储数据结构,保证元素唯一性的方式依赖于:hashCode() 于 equals() 方法。

    • 特点:无序集合,存储和取出的顺序不同,没有索引,不存储重复元素

    • 在代码编写上和 ArrayList 完全一致

    • 存储、取出数据都比较快

    • 线程不安全,运行速度快

    • 底层数据结构为哈希表(链表数组结合体)

    public static void main(String[] args)
    {
        //使用多态创建哈希表
        Set<String> S = new HashSet<>();
        S.add("abc");
        S.add("bcd");
        S.add("cde");
        //使用迭代器获取元素
        Iterator<String> it = S.iterator();
        while (it.hasNext())
        {
            System.out.println(it.next());
        }
        //使用增强获取元素
        for(String s : S)
        {
            System.out.println(s);
        }
    }

    2、HashSet 集合存储数据的结构(哈希表)

    哈希表介绍:

    哈希表底层使用的是数组机制,数组中也存放对象,而这些对象往数组中存放时的位置比较特殊,当需要把对象在这些数组中存放时,会根据这些对象特有的数据来结合相应的算法,计算出这个对象在数组中的位置,然后把这个对象存放在数组中。这样的数组就称为哈希数组,即哈希表。

    在哈希表存储数组时,会先记录第一个元素的地址,继续存储时,会让先来的元素记录后来的地址,在这里有一个“桶”和“加载因子”的概念,桶:数组的初始容量,初始容量为16;加载因子:数组的长度百分比,默认为0.75。数组的长度:16*0.75 = 12;当存放的数据超出数组长度 12 时,数组就会进行扩容,即复制(这个过程很耗费资源),这个过程也称为数据的再哈希 rehash。

    当向哈希表存放元素时,会根据元素的特有数据结合响应的算法,这个算法就是 Object 类中的 hashCode 方法。由于任何对象都是 Object 类的子类,所以任何对象都有这个方法,即:在哈希表中存放对象时,会调用对象的 hashCode 方法,算出对象在表中的位置,需要注意的是,如果两个对象 hashCode 方法算出结果一样,称为哈希冲突,这样会调用对象 equals 方法来比较两个对象是不是同一个对象,如果返回 true,则把第一个对象存放在哈希表中,如果返回 false,就会把这两个值都存放在哈希表中。

    总结:保证 HashSet 集合元素的唯一,其实就是根据对象 hashCode 和 equals 方法来决定的。如果往集合中存放自定义对象,为了保证唯一性,就必须重写 hashCode 和 equals 方法建立属于当前对象的比较方法。

    3、String 类的哈希值

    哈希值表示普通的十进制整数, 是父类 Object 方法 public int hashCode() 的计算结果,String 类继承了Object,重写了 hashCode 方法。String 类中 hashCode 源码:

    public int hashCode() {
        int h = hash;    //一开始变量 hash 为 0
        if (h == 0 && value.length > 0) {  
            char val[] = value;
            //返回字符串ASCII经过计算的和
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

    因此,当使用String类定义两个对象:String S1 = new String("abc"); String S2 = new String("abc"); 对象S1和S2哈希值是相同的,然后集合会让后来的对象调用 equals 方法,如果返回 true,则集合判定元素重复,将其去除。

    4、自定义对象重写hashCode和equals

    给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一。

    创建Person类,在类中重写 hashCode 方法和 equals 方法

    public class Person {
        private String name;
        private int age;
        public Person(String name,int age)
        {
            this.name = name;
            this.age = age;
        }
        public void setName(String name)
        {
            this.name = name;
        }
        public void setAge(int age)
        {
            this.age = age;
        }
        public String getName()
        {
            return name;
        }
        public int getAge()
        {
            return age;
        }
        public String toString() {
            return name + age;
        }
        //重写hashCode方法
        public int hashCode()
        {
            return name.hashCode() + age;
        }
        //重写equals方法
        public boolean equals(Object obj)
        {
            if(this == obj)
                return true;
            if(obj == null)
                return false;
            if(obj instanceof Person)
            {
                Person P = (Person)obj;
                return name.equals(obj.name) && age == P.age;
            }
            return false;
        }
    }

    在main中调用,由于重写了 hashCode 和 equals 方法,所以相同类型元素将不会打印出

    public static void main(String[] args)
    {
        //创建存储Person类的哈希表
        HashSet<Person> H = new HashSet<>();
        H.add(new Person("a",18));
        H.add(new Person("a",18));
        H.add(new Person("b",19));
        H.add(new Person("c",20));
        System.out.println(H);
    }

    5、LinkedHashSet集合

    LinkedHashSet 类是基于链表的哈希表的实现,继承自 HashSet,是 Set 接口的实现,此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。

    • LinkedHashSet  特点:具有顺序,存储和取出元素顺序相同
    public class LinkedHashSetDemo {
      
      public static void main(String[] args) {
    	LinkedHashSet<Integer> link = new LinkedHashSet<Integer>();
    	link.add(123);
    	link.add(44);
    	link.add(33);
    	link.add(33);
    	link.add(66);
    	link.add(11);
    	System.out.println(link);
      }
    }
    

    hashCode 和 equals 方法的面试题

    (1) 两个对象 Person P1 P2,如果两个对象的哈希值相同,则两个对象的 equals 一定返回 true 吗?

    不一定为 true

    (2) 两个对象 Person P1 P2,如果两个对象的 equals 方法返回 true,则两个对象的哈希值一定相同吗?

    一定相同

    展开全文
  • 使用Set集合对List集合进行去重

    万次阅读 2018-03-22 23:00:21
    使用Set集合对List集合进行去重前段时间正好遇到这样一个需求:我们的支付系统从对方系统得到存储明细对象的List集合,存储的明细对象对象的明细类简化为如下TradeDetail类,需求是这样的,我要对称List集合进行去重...
    使用Set集合对List集合进行去重

    前段时间正好遇到这样一个需求:我们的支付系统从对方系统得到存储明细对象的List集合,存储的明细对象对象的明细类简化为如下TradeDetail类,需求是这样的,我要对称List集合进行去重,这里的去重的意思是只要对象对象中的accountNo账号是相同的,就认为明细对象是相同的,去重之后要求是List集合或者Set集合。

    在进行上面的需求对象去重之前,先来看很简单的List集合去重:
    package com.qdfae.jdk.collections;

    import java.math.BigDecimal;
    import java.util.ArrayList;
    import java.util.Comparator;
    import java.util.HashSet;
    import java.util.Set;
    import java.util.TreeSet;

    import org.junit.Test;

    import com.qdfae.jdk.domain.TradeDetail;
    import com.qdfae.jdk.domain.User;

    /**
    * 使用Set集合对List集合进行去重
    *
    * @author hongwei.lian
    * @date 2018年3月9日 下午11:15:52
    */
    public class SetTest {
    /**
    * List集合的泛型为Integer类型
    *
    * @author hongwei.lian
    * @date 2018年3月9日 下午11:32:53
    */
    @Test
    public void testListToSet1() {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(1);
    Set<Integer> set = new HashSet<>(list);
    System.out.println("list的个数为:" + list.size() + "个");
    list.forEach(System.out::println);
    System.out.println("set的个数为:" + set.size() + "个");
    set.forEach(System.out::println);
    }
    /**
    * List集合的泛型为String类型
    *
    * @author hongwei.lian
    * @date 2018年3月9日 下午11:34:15
    */
    @Test
    public void testListToSet2() {
    List<String> list = new ArrayList<>();
    list.add("a");
    list.add("b");
    list.add("c");
    list.add("a");
    Set<String> set = new HashSet<>(list);
    System.out.println("list的个数为:" + list.size() + "个");
    list.forEach(System.out::println);
    System.out.println("set的个数为:" + set.size() + "个");
    set.forEach(System.out::println);
    }

    /**
    * List集合的泛型为自定义类型User
    * 需求是userCode一样的便是同一个对象
    *
    * @author hongwei.lian
    * @date 2018年3月10日 上午12:32:12
    */
    @Test
    public void testListToSet3() {
    List<User> list = new ArrayList<>();
    list.add(new User(1,"用户一","600001"));
    list.add(new User(2,"用户二","600002"));
    list.add(new User(3,"用户一","600001"));
    list.add(new User(4,"用户一","600001"));
    Set<User> set = new HashSet<>(list);
    System.out.println("list的个数为:" + list.size() + "个");
    list.forEach(System.out::println);
    System.out.println("set的个数为:" + set.size() + "个");
    set.forEach(System.out::println);
    }
    }
    上面测试使用到的User类源码:
    package com.qdfae.jdk.domain;

    import java.io.Serializable;

    /**
    * User实体类
    *
    * @author hongwei.lian
    * @date 2018年3月10日 上午12:33:22
    */
    public class User implements Serializable {
    private static final long serialVersionUID = -7629758766870065977L;

    /**
    * 用户ID
    */
    private Integer id;
    /**
    * 用户姓名
    */
    private String userName;
    /**
    * 用户代码
    */
    private String userCode;
    public User() {}
    public User(Integer id, String userName, String userCode) {
    this.id = id;
    this.userName = userName;
    this.userCode = userCode;
    }

    public Integer getId() {
    return id;
    }

    public void setId(Integer id) {
    this.id = id;
    }

    public String getUserName() {
    return userName;
    }

    public void setUserName(String userName) {
    this.userName = userName;
    }

    public String getUserCode() {
    return userCode;
    }

    public void setUserCode(String userCode) {
    this.userCode = userCode;
    }

    @Override
    public String toString() {
    return "User [id=" + id + ", userName=" + userName + ", userCode=" + userCode + "]";
    }
    }
    依次运行上面三个方法的结果是:
    testListToSet1()方法结果:

    testListToSet2()方法结果:

    testListToSet3()方法结果:

    上面的testListToSet1()方法和testListToSet2()方法可以去重,那为什么testListToSet3()方法就不能去重呢?仔细想想就会知道,两个对象的地址值不一样,怎么会认为是相同的去重呢,再往深处想,就会想到Object类的hashCode()方法和equals()方法,这两个方法决定了两个对象是否相等。Integer类和String类之所以可以进行去重,是因为这两个类都重写了父类Object类中的hashCode()方法和equals()方法,具体的代码可以去查看JDK源码,这里不再赘述。到这里我们就知道User对象不能去重的原因所在,那么我们根据需求在User类中重写hashCode()方法和equals()方法,重写后的User类源码如下:
    package com.qdfae.jdk.domain;

    import java.io.Serializable;

    /**
    * User实体类
    *
    * @author hongwei.lian
    * @date 2018年3月10日 上午12:33:22
    */
    public class User implements Serializable {
    private static final long serialVersionUID = -7629758766870065977L;

    /**
    * 用户ID
    */
    private Integer id;
    /**
    * 用户姓名
    */
    private String userName;
    /**
    * 用户代码
    */
    private String userCode;
    public User() {}
    public User(Integer id, String userName, String userCode) {
    this.id = id;
    this.userName = userName;
    this.userCode = userCode;
    }

    public Integer getId() {
    return id;
    }

    public void setId(Integer id) {
    this.id = id;
    }

    public String getUserName() {
    return userName;
    }

    public void setUserName(String userName) {
    this.userName = userName;
    }

    public String getUserCode() {
    return userCode;
    }

    public void setUserCode(String userCode) {
    this.userCode = userCode;
    }
    /**
    * 针对userCode重写hashCode()方法
    */
    @Override
    public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((userCode == null) ? 0 : userCode.hashCode());
    return result;
    }

    /**
    * 针对userCode重写equals()方法
    */
    @Override
    public boolean equals(Object obj) {
    if (this == obj)
    return true;
    if (obj == null)
    return false;
    if (getClass() != obj.getClass())
    return false;
    User other = (User) obj;
    if (userCode == null) {
    if (other.userCode != null)
    return false;
    } else if (!userCode.equals(other.userCode))
    return false;
    return true;
    }

    @Override
    public String toString() {
    return "User [id=" + id + ", userName=" + userName + ", userCode=" + userCode + "]";
    }
    }
    我们再次运行testListToSet3()方法结果:

    这一次符合我们的需求,接下里再来看开头提出的需求。
    准备:
    TradeDetail类源码:
    package com.qdfae.jdk.domain;

    import java.io.Serializable;
    import java.math.BigDecimal;

    /**
    * 交易明细
    *
    * @author hongwei.lian
    * @date 2018年3月10日 下午2:44:35
    */
    public class TradeDetail implements Serializable {
    private static final long serialVersionUID = 3386554986241170136L;

    /**
    * 交易明细主键
    */
    private Integer id;
    /**
    * 账号
    */
    private String accountNo ;
    /**
    * 账户名称
    */
    private String accountName;
    /**
    * 交易金额(+表示入金,-表示出金)
    */
    private BigDecimal balance;

    public TradeDetail() {}
    public TradeDetail(Integer id, String accountNo, String accountName, BigDecimal balance) {
    this.id = id;
    this.accountNo = accountNo;
    this.accountName = accountName;
    this.balance = balance;
    }

    public Integer getId() {
    return id;
    }

    public void setId(Integer id) {
    this.id = id;
    }
    public String getAccountNo() {
    return accountNo;
    }

    public void setAccountNo(String accountNo) {
    this.accountNo = accountNo;
    }

    public String getAccountName() {
    return accountName;
    }

    public void setAccountName(String accountName) {
    this.accountName = accountName;
    }

    public BigDecimal getBalance() {
    return balance;
    }

    public void setBalance(BigDecimal balance) {
    this.balance = balance;
    }
    /**
    * 针对accountNo重写hashCode()方法
    */
    @Override
    public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((accountNo == null) ? 0 : accountNo.hashCode());
    return result;
    }

    /**
    * 针对accountNo重写equals()方法
    */
    @Override
    public boolean equals(Object obj) {
    if (this == obj)
    return true;
    if (obj == null)
    return false;
    if (getClass() != obj.getClass())
    return false;
    TradeDetail other = (TradeDetail) obj;
    if (accountNo == null) {
    if (other.accountNo != null)
    return false;
    } else if (!accountNo.equals(other.accountNo))
    return false;
    return true;
    }

    @Override
    public String toString() {
    return "TradeDetail [id=" + id + ", accountNo=" + accountNo + ", accountName=" + accountName + ", balance="
    + balance + "]";
    }

    }
    我们首先来按照上面的想法根据需求重写TradeDetail类的hashCode()方法和equals()方法,上面已经给出重写后的TradeDetail类。
    我有三种实现方案如下:
    package com.qdfae.jdk.collections;

    import java.math.BigDecimal;
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.TreeSet;
    import java.util.stream.Collectors;

    import org.junit.Before;
    import org.junit.Test;

    import com.qdfae.jdk.domain.TradeDetail;

    /**
    * List集合去重
    *
    * @author hongwei.lian
    * @date 2018年3月11日 下午8:54:57
    */
    public class DuplicateListTest {
    /**
    * 存储没有去重的明细对象的List集合
    */
    private List<TradeDetail> tradeDetailList;
    /**
    * 存储去重后的明细对象的List集合
    */
    private List<TradeDetail> duplicateTradeDetailList;
    /**
    * 存储去重后的明细对象的Set集合
    */
    private Set<TradeDetail> tradeDetailSet;
    /**
    * 初始化tradeDetailList
    *
    * @author hongwei.lian
    * @date 2018年3月11日 下午9:04:45
    */
    @Before
    public void InitTradeDetailList() {
    tradeDetailList = new ArrayList<>();
    tradeDetailList.add(new TradeDetail(1, "600010", "账户一", new BigDecimal(100.00)));
    tradeDetailList.add(new TradeDetail(2, "600011", "账户二", new BigDecimal(100.00)));
    tradeDetailList.add(new TradeDetail(3, "600010", "账户一", new BigDecimal(-100.00)));
    tradeDetailList.add(new TradeDetail(4, "600010", "账户一", new BigDecimal(-100.00)));
    }

    /**
    * 使用Set接口的实现类HashSet进行List集合去重
    *
    * HashSet实现类
    * 构造方法:
    * public TreeSet(Comparator<? super E> comparator)
    *
    * @author hongwei.lian
    * @date 2018年3月11日 下午9:37:51
    */
    @Test
    public void testDuplicateListWithHashSet() {
    //-- 前提是TradeDetail根据规则重写hashCode()方法和equals()方法
    tradeDetailSet = new HashSet<>(tradeDetailList);
    tradeDetailSet.forEach(System.out::println);
    }
    /**
    * 使用Map集合进行List集合去重
    *
    * @author hongwei.lian
    * @date 2018年3月11日 下午9:05:49
    */
    @Test
    public void testDuplicateListWithIterator() {
    duplicateTradeDetailList = new ArrayList<>();
    Map<String, TradeDetail> tradeDetailMap = tradeDetailList.stream()
    .collect(Collectors.toMap(
    tradeDetail -> tradeDetail.getAccountNo(),
    tradeDetail -> tradeDetail,
    (oldValue, newValue) -> newValue));
    tradeDetailMap.forEach(
    (accountNo, tradeDetail) -> duplicateTradeDetailList.add(tradeDetail)
    );
    duplicateTradeDetailList.forEach(System.out::println);
    //-- 参考文章
    //http://blog.jobbole.com/104067/
    //https://www.cnblogs.com/java-zhao/p/5492122.html
    }
    /**
    * 使用Set接口的实现类TreeSet进行List集合去重
    *
    * TreeSet实现类
    * 构造方法:
    * public TreeSet(Comparator<? super E> comparator)
    *
    * @author hongwei.lian
    * @date 2018年3月11日 下午9:37:48
    */
    @Test
    public void testDuplicateListWithTreeSet() {
    tradeDetailSet = new TreeSet<>(
    (tradeDetail1, tradeDetail2)
    ->
    tradeDetail1.getAccountNo().compareTo(tradeDetail2.getAccountNo())
    );
    tradeDetailSet.addAll(tradeDetailList);
    tradeDetailSet.forEach(System.out::println);
    }

    }
    运行上面三个方法的结果都是:

    方案一:根据需求重写自定义类的hashCode()方法和equals()方法
    这种方案的不足之处是根据需求重写后的hashCode()方法和equals()方法不一定满足其他需求,这样这个TradeDetail类的复用性就会相当差。
    方案二:遍历List集合,取出每一个明细对象,将明细对象的accountNo属性字段作为Map集合key,明细对象作为Map集合的value,然后再遍历Map集合,得到一个去重后的List集合或者Set集合。
    这种方案的不足之处是消耗性能,首先是List集合去重转换为Map集合,Map集合再次转换为List集合或者Set集合,遍历也会消耗性能。
    方案三:使用TreeSet集合的独有的构造方法进行去重,如下:
    public TreeSet(Comparator<? super E> comparator) {
    this(new TreeMap<>(comparator));
    }
    这种方案目前为止是我使用的比较多的方案,不足之处暂时没有发现,TreeSet集合实际上是利用TreeMap的带有一个比较器参数的构造方法实现,看JDK源码很清晰,最重要的是这个参数Comparator接口,这个接口的源码:
    Comparator接口部分源码:
    @FunctionalInterface
    public interface Comparator<T> {

    int compare(T o1, T o2);

    }
    这个compare()方法需要自己根据需求去实现,仔细看上面去重的原理实际上还是使用String类的compareTo()方法,String类的compareTo()方法源码:
    public int compareTo(String anotherString) {
    int len1 = value.length;
    int len2 = anotherString.value.length;
    int lim = Math.min(len1, len2);
    char v1[] = value;
    char v2[] = anotherString.value;

    int k = 0;
    while (k < lim) {
    char c1 = v1[k];
    char c2 = v2[k];
    if (c1 != c2) {
    return c1 - c2;
    }
    k++;
    }
    return len1 - len2;
    }
    基本就想到了这些,如果有好的实现方法,自己还会补充。
    展开全文
  • JAVA集合之List集合遍历

    千次阅读 2019-01-25 22:59:20
    List集合的遍历 第一种根据集合的长度用for循环进行遍历 public static void main(String[] args) { List&amp;amp;lt;String&amp;amp;gt; arrayList = new ArrayList&amp;amp;lt;&amp;amp;...

    List集合的遍历
    第一种根据集合的长度用for循环进行遍历

    public static void main(String[] args) {
    		
    		List<String> arrayList = new ArrayList<>();
    		List<String> linkedList = new LinkedList<>();
    
    		for (int i = 0; i < 100000; ++i) {
    			arrayList.add(0,i+"");
    		}
    	
    		for (int i = 0; i < 100000; ++i) {
    			linkedList.add(0,i+"");
    		}
    		
    		Long arrStart = System.currentTimeMillis();
    		for(int i = 0; i < arrayList.size();i++) {
    			arrayList.get(i);
    		}
    		
    		Long arrTime = System.currentTimeMillis() - arrStart;
    		System.out.println("ArrayList的for循环遍历耗时:"+arrTime);
    		
    		Long linkedStart = System.currentTimeMillis();
    		for(int i = 0; i < linkedList.size();i++) {
    			linkedList.get(i);
    		}
    		
    		Long linkedTime = System.currentTimeMillis() - linkedStart;
    		System.out.println("LinkedList的for循环遍历耗时:"+linkedTime);
    	}
    

    结果为
    在这里插入图片描述
    用for循环遍历ArrayLis和LinkedList集合它们的耗时相差非常的大,因为ArryList集合支持根据索引来随机访问,所以用for循环遍历它非常快。而LinkedList的底层实现是链表,当它遍历一个数据时会将它前面的数据也遍历一遍所以它的耗时非常的多。ArrayList的get方法遍历数据的复杂度是O(1),而LinkedList的时间复杂度为O(N^2)

    第二种用foreach的方式遍历

    	public static void main(String[] args) {
    
    		List<String> arrayList = new ArrayList<>();
    		List<String> linkedList = new LinkedList<>();
    
    		for (int i = 0; i < 100000; ++i) {
    			arrayList.add(0, i + "");
    		}
    
    		for (int i = 0; i < 100000; ++i) {
    			linkedList.add(0, i + "");
    		}
    
    		Long arrStart = System.currentTimeMillis();
    		for (String arr : arrayList) {
    			arr = arr + "";
    		}
    		
    		Long arrTime = System.currentTimeMillis() - arrStart;
    		System.out.println("ArrayList的foreach循环遍历耗时:" + arrTime);
    
    		Long linkedStart = System.currentTimeMillis();
    		for (String linekd : linkedList) {
    			linekd = linekd + "";
    		}
    
    		Long linkedTime = System.currentTimeMillis() - linkedStart;
    		System.out.println("LinkedList的foreach循环遍历耗时:" + linkedTime);
    
    	}
    

    结果为
    在这里插入图片描述由上可以看出,当使用foreach方式来遍历ArrayList和LinkedList集合时,ArrayList集合的遍历时间相对于for循环遍历的方法有所增加。而且增加的幅度不是特别大,但是LinkedList集合的foreach遍历比for循环方式遍历所花的时间大大的减少了,性能提升非常大。并且用foreach方式遍历集合只需要一行代码就可以完成非常简洁,性能也很不错。所以在遍历List集合时推荐使用这种方法。

    第三种通过迭代器iterator的方式遍历

    public class Test {
    	public static void main(String[] args) {
    
    		List<String> arrayList = new ArrayList<>();
    		List<String> linkedList = new LinkedList<>();
    
    		for (int i = 0; i < 100000; ++i) {
    			arrayList.add(0, i + "");
    		}
    
    		for (int i = 0; i < 100000; ++i) {
    			linkedList.add(0, i + "");
    		}
    
    		Iterator<String> arrIterator = arrayList.iterator();
    		Long arrStart = System.currentTimeMillis();
    		while (arrIterator.hasNext()) {
    			arrIterator.next();
    		}
    		Long arrTime = System.currentTimeMillis() - arrStart;
    		System.out.println("ArrayList的iterator循环遍历耗时:" + arrTime);
    		
    		
    		Iterator<String> linkedIterator = arrayList.iterator();
    		Long linkedStart = System.currentTimeMillis();
    		while (linkedIterator.hasNext()) {
    			linkedIterator.next();
    		}
    		Long linkedTime = System.currentTimeMillis() - linkedStart;
    		System.out.println("LinkedList的iterator循环遍历耗时:" + linkedTime);
    
    	}
    
    

    结果为
    在这里插入图片描述

    从结果我们可以分析出iterator遍历ArrayList和用for循环遍历所花费的时间相差无几,因为ArrayList对于iterator中next方法的实现最终是通过数组下标获取元素来遍历的,和for循环通过get()方法来获取元素是一样的原理。通过iterator遍历LinkedList集合和通过foreach方法来遍历所花的时间也是接近的,因为foreach的底层也是通过调用iterator来遍历元素的。

    总结
    通过对三种遍历集合的方式我们可以知道它们的性能对比是iterator >= foreach > for。通过iterator和for循环来遍历ArrayList集合时时间相差不大,但是通过for循环来遍历LinkedList集合里的元素时所耗费的时间是无法承受的。因此不应当通过for循环来遍历LinkedList集合。通过foreach来遍历ArrayList集合和LinkedList集合都有很好的性能,而且它只需一行代码就可以完成遍历代码简洁。并且它不关心元素的下标可以避免下标越界的情况发生,因此遍历集合推荐使用foreach方式。

    说在最后
    本次的遍历性能对比都是在10万条数据下,因此具有一定的局限性仅仅作为一个参考。还希望大家可以自己动手多去尝试,如果有什么不正之处还望指教。

    展开全文
  • java集合之List集合

    千次阅读 2018-06-02 12:57:13
    关于集合以前也总结过一点,一直忘记摘录一下集合的继承关系图。核心收集接口封装了不同类型的集合,如下图所示。这些接口允许集合被独立地操纵它们表示的细节。核心收集接口是Java集合框架的基础。正如您在下图中所...
  • List集合的各种排序

    万次阅读 多人点赞 2019-02-15 17:56:39
    在Java编程中,经常要对List集合进行排序,因此对List排序的各种情况进行总结,希望对各位读者有所帮助。 1.单属性变量List排序 1.1按照变量属性升序,降序排序 /** * 单属性变量list 自身属性升序, 降序排序 ...
  • Java 中List集合特点

    千次阅读 2019-06-09 21:55:24
    开发工具与关键技术:MyEclipse 10、list集合 作者: 撰写时间:2019年06月06日   今天来了解java中集合,java集合类是一种特别有用的工具类,我们做项目或者做一些小程序也有可能用到它;可用于存储数量不等的...
  • java集合系列——List集合总结(六)

    万次阅读 2017-03-02 21:46:27
    List继承了Collection,是有序的列表。 实现类有ArrayList、LinkedList、Vector、Stack等 ArrayList是基于数组实现的,是一个数组队列。可以动态的增加容量! LinkedList是基于链表实现的,是一个双向循环列表。...
  • I . 定义集合并初始化 II . 集合泛型用法 III . 集合添加元素 IV . 集合生成函数 V . 集合遍历 VI . 集合示例代码
  • 1、集合框架(简介、Collection方法、迭代器) Collection就是相当容器 特殊的方法有iterator;相当于抓娃娃机中的夹子,把容器的元素取出的工具 《面试题 一.集合的remove方法与迭代器的remove方法有什么区别? 1.在...
  • List集合去重方式及效率对比

    千次阅读 2019-01-13 21:47:30
    List集合相信大家在开发过程中几乎都会用到。有时候难免会遇到集合里的数据是重复的,需要进行去除。然而,去重方式有好几种方式,你用的是哪种方式呢?去重方式效率是否是最高效、最优的呢?今天就给大家讲解一下...
  • 并发中的List集合

    千次阅读 2018-10-10 11:19:17
    实际开发中, 我们使用频率最高的容器估计是list集合,那肯定会遇并发操作.那该如何保证在多线程并发的环境下安全,高效的使用list集合呢?好,这就是今天我们聊话题:并发中的List集合. 家族体系 List: 有序集合(也...
  • Java8两个list集合合并成一个list集合

    万次阅读 2020-07-29 14:09:18
    java8 lambda小试牛刀,利用Stream把list转map,并将两个list的数据对象...// 集合1 List lists = new ArrayList<>(); SkillUpgrade s = new SkillUpgrade(); s.setLv(1); s.setAppearNum(100); lists.add(s); Ski
  • 如何将List集合去重

    千次阅读 2019-05-28 14:07:07
    众所周知List集合中的元素是有序的,但是List中的元素同样是可以重复的,那么我们应该怎么在List集合中去重呢? 方法一: 对于方法一而言,这也许是一个小窍门。利用的是Set集合中不允许出现重复的元素。 废话也不多...
  • List集合和Set集合的区别

    千次阅读 2019-06-09 22:06:51
    开发工具与关键技术:MyEclipse 10、list集合和Set集合的区别 作者: 撰写时间:2019年06月08日   List集合的详细特点:https://blog.csdn.net/weixin_43741599/article/details/91357999   Set集合类似于一个...
  • Kotlin 基础——List集合详解

    千次阅读 2020-04-14 13:14:46
    目录 一、声明和创建List集合 二、使用List的方法 三、可变的List List集合的最大特征就是集合元素都有对应的顺序索引。List集合允许使用重复元素,可以通过索引来访问指定位置的集合元素。 一、声明和创建List集合 ...
  • Java8 List集合过滤出符合条件的List元素集合 新增实体类 public class Student { private Integer stuNum; // 学号 private String name; // 姓名 private Integer age; // 年龄 省略set get 或加 @Data...
  • c#实现List集合

    千次阅读 2018-07-14 14:04:34
    List集合: 因为ArrayList(所有的数据都是以object数据类型存储)存在不安全类型与装箱拆箱的缺点,所以出现了泛型的概念。 List类是ArrayList类的泛型等效类,它的大部分用法都与ArrayList相似,因为List类...
  • JSON转List集合

    千次阅读 2019-06-24 15:37:54
    注意jar包不要导错了。 ... //第一种 JSONArray dataJson= JSONArray .fromObject(creaGathering); List<CreaUserTemplate> list = (List<CreaUserTemplate>) JSONArray.toCollection(...
  • List集合底层原理

    千次阅读 2019-05-21 20:59:28
    List集合代表一个有序集合,集合中每个元素都有其对应的顺序索引。List集合允许使用重复元素,可以通过索引来访问指定位置的集合元素。 List接口继承于Collection接口,它可以定义一个允许重复的有序集合。因为List...
  • List集合去除重复对象

    千次阅读 2019-03-21 21:28:51
    在java中,要将一个List中重复的对象除去,如果这个集合中的数据类型是基本数据类型,可以直接将List集合转换成Set,就会自动去除重复的元素,大家都知道Set集合的特点就是没有重复的,这个就相对比较简单,这里不在...
  • 多线程分段处理List集合

    千次阅读 2018-05-27 22:36:47
    场景:大数据List集合,需要对List集合中的数据同标准库中数据进行对比,生成新增,更新,取消数据 解决方案:List集合分段,动态创建线程池newFixedThreadPool将对比操作在多线程中实现public static void main(String[] ...
  • JAVA中List集合Stream流详解

    千次阅读 2020-03-21 17:06:15
    1、Stream流介绍 在JDK8时,JAVA新增了lambda表达式,它与java.io包里的InputStream和OutputStream是完全不同的概念,他更跟流没有任何关系。...JDK8 中的 Stream 是对集合(Collection)对象功能的增强,...
  • postman传递list集合后台springmvc接受

    万次阅读 热门讨论 2018-11-21 18:53:43
    在做项目的时候我们可能会遇见一些场景需要前端给后端传递某个实体类的集合,这个时候后端的接口写完了,需要进行接口的测试,这里我使用的是postman进行接口测试,下面写下在用postman进行接口测试传递list集合的...
  • 今天来比较一下两个list,然后分别找出相同元素和不同元素的集合。先上一个简单的示例:(注:因为测试数据量比较小,用ArrayList,如果涉及到百万数据的插入移除操作的话,用LinkedList)[java] view plain copy&...
  • List集合与泛型(详细篇)

    千次阅读 多人点赞 2019-02-24 11:29:12
     集合泛型父类可以添加子类集合list1.addAll(list2);list2的泛型是list1的子类. 八、集合框架,增强for循环  增强for循环底层依赖迭代器(Iterator)  快捷键 输入fore 按alt+/  3种迭代方法(普通for循环...
  • JSON字符串转List集合操作

    千次阅读 2019-03-28 20:56:03
    JSON字符串转List集合List集合转JSON字符串 使用的jar包是fastjson-1.2.41.jar 1.JSON字符串转List集合操作 public static <T> List<T> parseArray(String text, Class<T> clazz) { try { ...
  • List集合的交集,差集,和并集

    千次阅读 2019-11-04 17:25:46
    1.交集: @Test public void testRemove(){ List<String> list=new ArrayList<>(); list.add("1"); list.add("2") ; list.add("19"); ...
  • 【java】list集合之元素查重

    千次阅读 2018-09-30 19:58:41
    文章目录list集合之元素查重 前言 代码 验证结果 list集合之元素查重 前言 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在将excel表格中的数据插入到数据库中之前,会先进行...
  • List<Student> students = getAllStudents(); //从所有学生集合中获取名字集合 List<String> supplierCodes = students.stream().map(Student :: getName).collect(Collectors.toList()); students:...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,032,820
精华内容 413,128
关键字:

list集合