Java知识点04——集合(Set、List、Queue、Map、Collection和Iterator、Collections工具类)

声明:

  1. 该资料来自自己整理。
  2. 参考书籍 疯狂 Java讲义(第五版) 李刚©著

一、集合

1.1 集合概述

概念对象的容器,定义了对多个对象进项操作的的常用方法。可实现数组的功能

  • 集合和数组区别?

    (1)数组的长度是固定的。集合的长度是可变的
    (2)数组可以存储基本类型和引用类型,集合只能存储引用类型。而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。

  • 位置: java.util.*;

如果访问List集合中的元素,可以直接根据元素的索引来访问;
如果访问Map集合中的元素,可以根据每项元素的key来访问其value;
如果访问Set集合中的元素,则只能根据元素本身来访问(这也是Set集合里元素不允许重复的原因);

集合本身是一个工具,它存放在java.util包中。在Collection接口定义着单列集合框架中最最共性的内容。

二、Collection

2.1 介绍


Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合。方法如下:

  • boolean add(Object o): 用于向集合里添加一个元素。如果集合对象被添加操作改变了,则返回true。(把给定的对象添加到当前集合中 。)
  • boolean addAll(Collection c):用于把集合 c 里面的所有元素添加到指定集合里。如果集合对象被添加操作改变了,则返回true。
  • void clear() :清空集合中所有的元素,将集合长度变为0。
  • boolean remove(Object o): 把指定的元素从当前集合中删除,当集合中包含了一个或多个元素 o 时,该方法只删除第一个符合条件的元素,该方法返回true。
  • boolean removeAll(Collection c): 从集合中删除集合 c 里包含的所有元素(相当于调用该方法的集合减集合 c ),如果删除了一个或一个以上的元素,该方法返回true。
  • boolean retainAll(Collection c):从集合中删除集合 c 里不包括的元素(相当于把调用该方法的集合变成该集合和集合 c 的交集),如果该操作改变了调用该方法的集合,则该方法返回true。
  • boolean contains(Object o): 判断当前集合中是否包含指定元素。
  • boolean containsAll(Collection c):判断集合里是否包含集合 c 里的所有元素。
  • boolean isEmpty(): 判断当前集合是否为空。当前集合长度为 0 时返回true,否则返回false。
  • int size(): 返回集合中元素的个数。
  • Object[] toArray(): 把集合中的元素,存储到数组中,所有的集合元素变成对应的数组元素。

2.2 操作集合

在这里插入图片描述

2.3 操作案例

public class CollectionTest {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        
        //添加元素
        c.add("孙悟空");
        c.add(6);//虽然集合里不能放基本类型的值,但Java支持自动装箱
        c.add(true);
        //输出集合c
        System.out.println(c);//[孙悟空, 6, true] //按存储时的顺序读取
        
        //遍历c集合
        for (Object o : c) {
            System.out.print(o+",");//孙悟空,6,true,
        }
        System.out.println();
        
        //删除指定元素
        c.remove(true);
        System.out.println("c集合的元素个数:"+c.size());//c集合的元素个数:2
        
        //判断集合c中是否包含指定字符串(元素)
        System.out.println("c集合中是否包含\"孙悟空\"字符串:"+c.contains("孙悟空"));//true
        
        //c集合转换成Object数组
        Object[] objects = c.toArray();
        System.out.println(objects);//[Ljava.lang.Object;@6d6f6e28
        System.out.println(c);//[孙悟空, 6]
        
        //forEach遍历objects数组
        for (Object o:objects) {
            System.out.print(o+",");//孙悟空,6,
        }
        System.out.println();
        //for遍历数组objects
        for (int i = 0; i < objects.length; i++) {
            System.out.print(objects[i]+",");//孙悟空,6,
        }
        System.out.println();

        Collection books = new HashSet();
        
        //向Set集合中添加元素
        books.add("Java讲义");
        books.add("php进阶教程");
        books.add("孙悟空");
        System.out.println(books);//[php进阶教程, 孙悟空, Java讲义] // 随机读取
        for (Object bo:books ) {
            System.out.print(bo+",");//php进阶教程,孙悟空,Java讲义, // 随机遍历
        }
        System.out.println();
        System.out.println("c集合是否包含\"孙悟空\"元素:"+books.contains("孙悟空"));//c集合是否包含"孙悟空"元素:true
        System.out.println("c集合中是否完全包含books集合?"+c.containsAll(books));//c集合中是否完全包含books集合?false
        
        //用 c 集合减去books集合里的元素(相当于把c集合中包含在bookes集合中的元素删除掉)
        c.removeAll(books);
        System.out.println(c);//[6]
        
        //删除c集合里的所有元素
        c.clear();
        System.out.println("c集合中的元素:"+c);//c集合中的元素:[]
        
        //判断c集合是否为空
        System.out.println("c集合是否为空:"+c.isEmpty());//c集合是否为空:true
        
        //返回c集合中元素的个数
        System.out.println("c集合中元素个数:"+c.size());//c集合中元素个数:0
        
        //从books集合中删除c集合中不含有的元素
        books.retainAll(c);
        System.out.println("books集合中的元素:"+books);//books集合中的元素:[]
    }
}

tips:有关Collection中的方法可不止上面这些,其他方法可以自行查看API学习。

三、Set 集合

3.1 介绍

3.2 HashSet

HashSet是采用哈希算法实现,底层实际是用HashMap实现的(HashSet本质就是一个简化版的HashMap),因此,查询效率和增删效率都比较高

3.2.1 特点

  • 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也可能发生变化。
  • HashSet不是同步的,如果多个线程同时访问一个HashSet,假设有两个或两个以上线程同时修改了HashSet集合时,则必须通过代码来保证其同步。
  • 集合元素值可以是null。



HashSet会根据元素的hashCode值来计算它的存储位置,从而快速定位该元素的位置。

  • 当从HashSet中访问元素时,HashSet先计算该元素的hashCode()值(也就是调用该对象的hashCode()方法的返回值),然后直接到该hashCode值对应的位置去取出该元素----这就是HashSet速度很快的原因。

3.2.2 操作案例(重写hashCode和equals方法)

import java.util.HashSet;
import java.util.Iterator;
import java.util.Objects;

class R{
    int count;
    public R(){}
    public R(int count){
        this.count  = count;
    }
    public String toString(){
        return "R[coutn:"+count+"]";
    }
    
	//重写的hashCode方法;
    //当HashSet集合对象调用add()方法时,
    //会拿该要添加的对象跟集合中已经添加的对象调用hashCode()方法进行比较。
    //从而来保证添加的元素不重复(跟equals方法同时协调使用)
    @Override
    public int hashCode() {
        return this.count;
    }
    
	//重写的equals方法;
    //当HashSet集合对象调用add()方法时,
    //会拿该要添加的对象跟集合中已经添加的对象调用equals()方法进行比较。
    //从而来保证添加的元素不重复(跟hashCode方法同时协调使用)
    @Override
    public boolean equals(Object obj) {
        if (this == obj){
            return false;
        }
        if (obj != null && obj.getClass() == getClass()){
            R r = (R)obj;
            return this.count == r.count;
        }
        return false;
    }
}

public class HashSetTest2 {
    public static void main(String[] args) {
        R rr = new R(10);
        System.out.println(rr);//R[coutn:10]
        System.out.println(rr.toString());//R[coutn:10]

        HashSet<R> hs = new HashSet();
        hs.add(new R(2));
        hs.add(new R(-3));
        hs.add(new R(9));
        hs.add(new R(2));
        hs.add(new R(-5));
        //打印HashSet集合,集合元素没有重复
        System.out.println(hs);//[R[coutn:2], R[coutn:-3], R[coutn:-5], R[coutn:9]]
        //取出第一个元素
        Iterator it = hs.iterator();
        R first = (R)it.next();
        //为第一个元素的count实例变量赋值
        //导致HashSet集合中出现相同的值
        first.count = -3;
        System.out.println(hs);//[R[coutn:-3], R[coutn:-3], R[coutn:-5], R[coutn:9]]
        //删除count为-3的R对象
        hs.remove(new R(-3));
        System.out.println(hs);//[R[coutn:-3], R[coutn:-5], R[coutn:9]]

		//此时查看 new R(-3)(在原本第二个位置) 时出错,如下:
        System.out.println("hs是否包含count为-3的R对象?"+ hs.contains(new R(-3)));//false
        System.out.println("hs是否包含count为-5的R对象?"+ hs.contains(new R(-5)));//true
        System.out.println("hs是否包含count为2的R对象?"+ hs.contains(new R(2)));//false
    }
}

3.3 LinkedHashSet

LinkedHashSet,它是链表 和 哈希表组合的一个数据存储结构。

注意:输出LinkedHashSet集合元素时,元素的顺序总是与添加顺序一致。

import java.util.LinkedHashSet;
import java.util.LinkedList;

public class LinkedHashSetTest {
    public static void main(String[] args) {
        LinkedHashSet books = new LinkedHashSet();
        books.add("疯狂原始人");
        books.add("寻梦环游记");
        System.out.println(books);//[疯狂原始人, 寻梦环游记]
        //删除 疯狂原始人
        books.remove("疯狂原始人");
        System.out.println(books);//[寻梦环游记]
        //重新添加
        books.add("疯狂原始人");
        System.out.println(books);//[寻梦环游记, 疯狂原始人]
    }
}

3.4 TreeSet

TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态

与HashSet集合相比,TreeSet还提供了如下几个额外的方法:

  • Comparator comparator():如果TreeSet采用了制定排序,则该方法返回定制排序所使用的Compatator;如果TreeSet采用了自然排序,则返回null。
  • Object first():返回集合中的第一个元素。
  • Object last():返回集合中的最有一个元素。
  • Object lower(Object e):返回集合中位于指定元素之前的元素(即小于指定元素的最大元素,参考元素不需要是TreeSet集合里的元素)。
  • Object higher(Object e):返回集合中位于指定元素之后的元素(即大于指定元素的最小值,参考元素不需要时TreeSet集合里的元素)。
  • SortedSet headSet(Object fromElement,Object toElement):返回Set的子集合,范围从fromElement(包含) 到 toElement(不包含)。
  • SortedSet headSet(Object toElement):返回此Set的子集,由小于toElement的元素组成。
  • SortedSet tailSet(Object fromElement):返回此Set的子集,由大于或等于fromElement的元素组成。


【案例】

import java.util.TreeSet;

public class TreeSetTest {
    public static void main(String[] args) {
        TreeSet nums = new TreeSet();
        //向TreeSet中添加4个Integer对象
        nums.add(3);
        nums.add(2);
        nums.add(1);
        nums.add(-4);
        //输出集合元素,看到集合元素已经处于排序状态
        System.out.println(nums);//[-4, 1, 2, 3]
        //输出集合中的第一个元素
        System.out.println(nums.first());//-4
        //输出集合中的最后一个元素
        System.out.println(nums.last());//3
        //返回小于2的子集,不包含2
        System.out.println(nums.headSet(2));//[-4, 1]
        //返回大于1的子集,包含1
        System.out.println(nums.tailSet(1));//[1, 2, 3]
        //返回大于等于2小于4的子集
        System.out.println(nums.subSet(2,4));//[2, 3]
    }
}

3.4.1 自然排序





【案例】

import java.util.TreeSet;

public class TreeSetTest {
    public static void main(String[] args) {
        TreeSet nums = new TreeSet();
        //向TreeSet中添加4个Integer对象
        nums.add(3);
        nums.add(2);
        nums.add(1);
        nums.add(-4);
        //输出集合元素,看到集合元素已经处于排序状态
        System.out.println(nums);//[-4, 1, 2, 3]
    }
}

3.4.2 定制排序(重点)


【案例】

import java.util.TreeSet;

class M{
    int age;
    public M(int age){
        this.age = age;
    }
    public String toString(){
        return "M [age="+age+"]";
    }
}

public class CustomizedSort {
    public static void main(String[] args) {
        //使用Lambda表达式来代替Comparator接口
        TreeSet ts = new TreeSet(((o1, o2) -> {
            M m1 = (M)o1;
            M m2 = (M)o2;
            //根据M对象的age属性来决定大小,age越大,M对象反而越小(降序)
            //return m1.age > m2.age ? -1 : m1.age < m2.age ? 1 :0;
            //根据M对象的age属性来决定大小,age越大,M对象越大(升序)
            return m1.age > m2.age ? 1 : m1.age < m2.age ? -1 : 0;
        }));
        ts.add(new M(5));
        ts.add(new M(-3));
        ts.add(new M(9));
        ts.add(new M(2));
        //降序时输出
        //System.out.println(ts);//[M [age=9], M [age=5], M [age=2], M [age=-3]]
        //升序时输出
        System.out.println(ts);//[M [age=-3], M [age=2], M [age=5], M [age=9]]
    }
}

四、List 集合

4.1 介绍

4.2 ArrayList

ArrayList 是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。

特点:查询效率高,增删效率低,线程不安全

  • java.util.ArrayList 是大小可变的数组的实现,存储在内的数据称为元素。此类提供一些方法来操作内部存储的元素。 ArrayList 中可不断添加元素,其大小也自动增长。

4.3 LinkedList

LinkedList 底层用双向链表实现的存储。

特点:查询效率低,增删效率高,线程不安全

五、Queue 集合

六、Map 集合

6.1 常用函数

Map接口中定义了很多方法,常用的如下:

  • int size():返回该Map里的key-value对的个数。

  • void clear():删除该Map对象中的所有 key-value 对。

  • boolean isEmpty():查询该Map是否为空(即不包含任何key-value对),如果为空则返回ture。

  • Object put(Object key, Object value): 添加一个 key-value 对,如果当前Map中已有一个与该key相等的 key-value 对,则心得key-value对会覆盖原来的key-value对。

  • void putAll(Map m):将指定Map中的 key-value 对复制到本Map中。

  • Object remove(Object key):删除指定key所对应的key-value对,返回被删除key所关联的value,如果该key不存在,则返回null。

  • Object remove(Object key,Object value):删除指定key、value所对应的key-value对。如果从该Map中成功删除该key-value对,该方法返回true,否则返回false。

  • Object get(Object key) :返回指定 key 所对应的value;如果此Map中不包含该key,则返回null。

  • boolean containsKey(Object key) :查询Map中是否包含指定的 key,如果包含则返回true。

  • boolean containsValue(Object value):查询Map中是否包含一个或多个value,如果包含则返回true。

  • Set<K> keySet():返回该Map中所有key组成的Set集合。

  • Collection values():返回该Map里所有value组成的Collection。

  • Set<Map.Entry<K,V>> entrySet(): 返回Map中包含的key-value 对所组成的Set集合,每个集合元素都是 Map.Entry(Entry是Map的内部类)对象。

6.2 HashMap

import java.util.HashMap;

public class MapTest01 {
    public static void main(String[] args) {
        //创建map对象
        HashMap<String,String> map = new HashMap<>();
        
        //添加元素
        map.put("上","下");
        map.put("up","down");
        map.put("me","you");
        
        //添加元素返回该键值在map中对应的值(不是当前key的value)
        //如果map中没有该值,则返回null
        System.out.println(map.put("xx","yy"));//null
        System.out.println(map.put("xx","zz"));//yy
        System.out.println(map);//{xx=zz, me=you, 上=下, up=down}
        
        //remove(V key) 返回所删除key值对应的value
        System.out.println(map.remove("上"));//下
        System.out.println(map.remove("hhhh"));//null
        System.out.println(map);//{xx=zz, me=you, up=down}
        
        //map.get(V key)获取 返回指定 key 所对应的value;如果此Map中不包含该key,则返回null
        System.out.println("up的value:"+map.get("up"));//up的value:down
        System.out.println("hh的value:"+map.get("hh"));//hh的value:null
    }
}

集合遍历键找值【案例】

import java.util.HashMap;
import java.util.Set;

public class FindKeysValue {
    public static void main(String[] args) {
        HashMap<String,String> map = new HashMap<>();
        map.put("数字","123");
        map.put("字母","abc");
        map.put("汉字","你好");
        
        //获取所有key,存入Set集合
        Set<String> keys = map.keySet();
        
        //遍历键集
        for (String key:keys){
            //根据key获得对应的value
            String value = map.get(key);
            System.out.println(key+":对应的值是:"+value);
        }
    }
}


自定义类型键值【案例】

import java.util.Objects;

//注意,学生姓名相同并且年龄相同视为同一名学生。
public class Student {
    private String name;
    private int age;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
	//重写hashCode()方法
    @Override
    public int hashCode() {
        return Objects.hash(name,age);
    }
	//重写equals()方法
    @Override
    public boolean equals(Object obj) {
        if (this == obj){
            return true;
        }
        if (obj == null || getClass() != obj.getClass()){
            return false;
        }
        Student student = (Student) obj;
        return age == student.age && Objects.equals(name,student.name);
    }
	//重写toString()方法
    @Override
    public String toString() {
        return "Student{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}
public class HashMapCustomTest {
    public static void main(String[] args) {
        Map<Student,String> map = new HashMap<>();
        map.put(new Student("李四",28),"上海");
        map.put(new Student("王五",18),"广州");
        map.put(new Student("赵六",23),"南京");
        map.put(new Student("小红",13),"北京");
        map.put(new Student("许褚",32),"哈尔滨");
        map.put(new Student("刘备",23),"洛阳");
        
        //取出key值,存入Set集合
        Set<Student> ss = map.keySet();
        
        for (Student s:ss){
            //记得重写Student类中的toString方法,否则返回的是对象的地址
            System.out.println(s+" --> "+map.get(s));
        }
    }
}

  • 当给HashMap中存放自定义对象时,如果自定义对象作为key存在,这时要保证对象唯一,必须复写对象的hashCode和equals方法(如果忘记,请回顾HashSet存放自定义对象)。
  • 如果要保证map中存放的key和取出的顺序一致,可以使用java.util.LinkedHashMap集合来存放。

tips:

  1. 使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中; 若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。

6.3 LinkedHashMap

HashMap保证成对元素唯一,并且查询速度很快,可是成对元素存放进去是没有顺序的,那么我们要保证有序,还要速度快怎么办呢?

在HashMap下面有一个子类LinkedHashMap,它是链表和哈希表组合的一个数据存储结构。

public class LinkHashMapTest {
    public static void main(String[] args) {
    
        LinkedHashMap<String,Integer> lmp = new LinkedHashMap<>();
        lmp.put("zhangsan",1);
        lmp.put("lisi",2);
        lmp.put("wangwu",3);
        
        Set<Map.Entry<String,Integer>> ss = lmp.entrySet();
        
        for (Map.Entry<String,Integer> s:ss){
            System.out.println("key:"+s.getKey()+",value:"+s.getValue());
        }
    }
}

6.4 Entry(内部类)

  我们已经知道,Map中存放的是两种对象,一种称为key(键),一种称为value(值),它们在在Map中是一一对应关系,这一对对象又称做Map中的一个Entry(项)Entry将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对(Entry)对象中获取对应的键与对应的值。

常用方法

  • Object getKey():返回该Entry里包含的key值。
  • Object getValue():返回该Entry里包含的value值。
  • Object setValue(V value):设置该Entry里包含的value值,并返回新设置的value值。

在Map集合中也提供了获取所有Entry对象的方法:

  • Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。

获取遍历

键值对方式:即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值。

操作步骤与图解:

  1. 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。方法提示:Ojbect.entrySet()
  2. 遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象。
  3. 通过键值对(Entry)对象,获取Entry对象中的键与值。 方法提示:getkey() 和 getValue()
public class MapEntryForeach {
    public static void main(String[] args) {
        HashMap<String,String> map = new HashMap<>();
        map.put("数字","123");
        map.put("字母","abc");
        map.put("汉字","你好");
        
        //获取所有 entry对象 ,entrySet
        Set<Map.Entry<String,String>> entrySet = map.entrySet();
        
        //遍历
        for (Map.Entry<String,String> entry: entrySet){
            //从entrySet对象中获取键
            String key = entry.getKey();
            //从entrySet对象中获取值
            String value = entry.getValue();
            System.out.println(key+"-->"+value);
        }
    }
}

七、Iterator 接口(迭代器)

7.1 介绍


  在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,JDK专门提供了一个接口java.util.IteratorIterator接口也是Java集合中的一员,但它与CollectionMap接口有所不同,Collection接口与Map接口主要用于存储元素,而Iterator主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。

想要遍历Collection集合,那么就要获取该集合迭代器完成迭代操作,下面介绍一下获取迭代器的方法:

  • public Iterator iterator(): 获取集合对应的迭代器,用来遍历集合中的元素的。

下面介绍一下迭代的概念:

  迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。

7.2 常用方法

  • Object next():返回集合里的下一个元素。
  • boolean hasNext():如果仍有元素可以迭代,则返回 true。
  • void remove():删除集合里的上一次next方法返回的元素。
  • void forEachRemaining(Consumer action):jdk 1.8新增的默认方法,该方法可使用Lambda表达式来遍历集合元素。

使用Iterator迭代集合中元素:【案例】

public class IteratorTest {
    public static <Stirng> void main(String[] args) {
    
        //创建集合、添加元素
        Collection<String> books = new HashSet<>();
        books.add("疯狂原始人");
        books.add("元神");
        books.add("LOL");
        
        //获取books集合对应的迭代器
        Iterator it = books.iterator();
        System.out.println(it);//java.util.HashMap$KeyIterator@6d6f6e28
        System.out.println(it.next());//元神
        for (Iterator iter = it; iter.hasNext(); ) {
            String s = (String) iter.next();
            System.out.print(s+",");//疯狂原始人,LOL,
        }
        System.out.println();

        //直接使用next()方法如果集合中没有可迭代的下一个元素将发生异常
        //books.clear();
        //it.next();//java.util.ConcurrentModificationException

        //使用hasNext()方法判断books集合中是否还有下一个可迭代的元素
        while (it.hasNext()){
            //it.next()方法返回集合里的下一个元素
            //it.next()方法返回的数据类型是Object类型,因此需要进行强制类型转换
            String book = (String)it.next();
            System.out.println("book:"+book);//book:元神 //book:疯狂原始人 //book:LOL
            if (book.equals("元神")){
                //从集合中删除上一次next()方法返回的元素
                it.remove();
            }
            //对book变量赋值,不会改变集合元素本身
            book = "测试字符串";
            System.out.println(book);//测试字符串 //测试字符串 //测试字符串
        }
        System.out.println(books);//[疯狂原始人, LOL]
    }
}


tips

  1. 在进行集合元素取出时,如果集合中已经没有元素了,还继续使用迭代器的next方法,将会发生java.util.ConcurrentModificationException并发异常。
  2. 当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。

迭代器的实现原理

  当遍历集合时,首先通过调用t集合的iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在,则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。

  Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素,为了让初学者能更好地理解迭代器的工作原理,接下来通过一个图例来演示Iterator对象迭代元素的过程:

  在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,不指向任何元素,当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next方法时,迭代器的索引会指向第二个元素并将该元素返回,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。

7.3 增强for(forEach)

  增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。

格式

for(元素的数据类型  变量 : Collection集合 或 数组){ 
  	//写操作代码
}

它用于遍历Collection和数组。通常只进行遍历元素,不要在遍历的过程中对集合元素进行增删操作。

7.3.1 遍历数组

public class NBForDemo1 {
    public static void main(String[] args) {
		int[] arr = {3,5,6,87};
       	//使用增强for遍历数组
		for(int a : arr){//a代表数组中的每个元素
			System.out.println(a);
		}
	}
}

7.3.2 遍历集合

public class NBFor {
    public static void main(String[] args) {        
    	Collection<String> coll = new ArrayList<String>();
    	coll.add("小河神");
    	coll.add("老河神");
    	coll.add("神婆");
    	//使用增强for遍历
    	for(String s :coll){//接收变量s代表 代表被遍历到的集合元素
    		System.out.println(s);
    	}
	}
}

tips:新for循环必须有被遍历的目标。目标只能是Collection或者是数组。新式for仅仅作为遍历操作出现。

八、Collections 工具类

java.util.Collections 类提供了对Set、List、Map集合进行排序、填充、查找元素的辅助方法。

8.1 排序

常用方法

  • void reverse(List list):反转指定List集合中元素顺序。
  • void shuffle(List list):对List集合元素进行随机排序(shuffle方法模拟了“洗牌”动作)。
  • void sort(List list):根据元素的自然顺序对指定List集合的元素按升序进行排序。
  • void sort(List list,Comparator c):根据指定Comparator产生的顺序对List集合元素进行排序。
  • void swap(List list,int i,int j):将指定List集合中的 i 处的元素和 j 处的元素进行交换。
  • void rotate(List list,int distance):当distance为正数时,将list集合的后distance个元素“整体”移到前面;当distance为负数时,将list集合的前distance个元素“整体”移到后面。该方法不会改变集合的长度。

8.2 查找、替换

  • int binarySearch(List list, Object key), 对List进行二分查找,返回索引,注意List必须是有序的
  • int max(Collection coll),根据元素的自然顺序,返回最大的元素。 类比int min(Collection coll)
  • int max(Collection coll, Comparator c),根据定制排序,返回最大元素,排序规则由Comparatator类控制。类比int min(Collection coll, Comparator c)
  • void fill(List list, Object obj),用元素obj填充list中所有元素
  • int frequency(Collection c, Object o),统计元素出现次数
  • int indexOfSubList(List list, List target), 统计targe在list中第一次出现的索引,找不到则返回-1,类比int lastIndexOfSubList(List source, list target).
  • boolean replaceAll(List list, Object oldVal, Object newVal), 用新元素替换旧元素。

8.3 Comparable 接口

8.3.1 单条件 排序

如果想使用Collections.sort(List list);对 对象集合 进行指定规则的排序,则该对象所在的类必须继承Comparable< E >接口,否则报错

public class StudentImplementComparable implements Comparable<StudentImplementComparable>{
    private int age;
    private String name;
    private double weight;

    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;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public StudentImplementComparable() {
    }

    public StudentImplementComparable(int age, String name, double weight) {
        this.age = age;
        this.name = name;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "StudentImplementComparable{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", weight=" + weight +
                '}';
    }

    @Override
    public int compareTo(StudentImplementComparable o) {
        //按年龄升序排列
        return (this.age < o.age) ? -1 : ((this.age == o.age) ? 0 : 1);
        //按年龄降序排列
        //return -((this.age < o.age) ? -1 : ((this.age == o.age) ? 0 : 1));
    }
}
public class StudentImplementComparableTest {
    public static void main(String[] args) {
        ArrayList<StudentImplementComparable> sl = new ArrayList<>();
//        sl.add(new StudentImplementComparable(12,"张三",12.3));
//        sl.add(new StudentImplementComparable(15,"李四",33.1));
//        sl.add(new StudentImplementComparable(20,"王五",25.2));
//        sl.add(new StudentImplementComparable(10,"许褚",10.0));
        Collections.addAll(sl,
                new StudentImplementComparable(12,"张三",12.3),
                new StudentImplementComparable(15,"李四",33.1),
                new StudentImplementComparable(20,"王五",25.2),
                new StudentImplementComparable(10,"许褚",10.0)
                );
        Collections.sort(sl);//调用排序方法(调用sl集合对象所在类里面重写的comparaTo(E e)方法)
        for (StudentImplementComparable s: sl) {
            System.out.println(s);
        }
    }
}


8.3.2 多条件 排序

	//修改重写的 compareTo 方法
	@Override
    public int compareTo(StudentImplementComparable o) {
        //按年龄升序排列
        //return (this.age < o.age) ? -1 : ((this.age == o.age) ? 0 : 1);
        //按年龄降序排列
        //return -((this.age < o.age) ? -1 : ((this.age == o.age) ? 0 : 1));
        
        //按照年龄升序排列,年龄相同的话再按体重升序排列
        if (this.age == o.age){
            return (this.weight < o.weight) ? -1 : ((this.weight == o.weight) ? 0 : 1);
        }else{
            return (this.age < o.age) ? -1 : 1;
        }
    }
		Collections.addAll(sl,
                new StudentImplementComparable(12,"张三",12.3),
                new StudentImplementComparable(15,"李四",33.1),
                new StudentImplementComparable(20,"王五",25.2),
                new StudentImplementComparable(20,"刘备",56.8),
                new StudentImplementComparable(10,"许褚",10.0)
                );
        Collections.sort(sl);
        for (StudentImplementComparable s: sl) {
            System.out.println(s);
        }

8.4 Comparator 接口

void Collections.sort(List<T> list,Comparator<? super T> c)

public class StudentImplementComparable {
    private int age;
    private String name;
    private double weight;

    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;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public StudentImplementComparable() {
    }

    public StudentImplementComparable(int age, String name, double weight) {
        this.age = age;
        this.name = name;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "StudentImplementComparable{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", weight=" + weight +
                '}';
    }
}
public class StudentImplementComparableTest {
    public static void main(String[] args) {
        ArrayList<StudentImplementComparable> sl = new ArrayList<>();
//        sl.add(new StudentImplementComparable(12,"张三",12.3));
//        sl.add(new StudentImplementComparable(15,"李四",33.1));
//        sl.add(new StudentImplementComparable(20,"王五",25.2));
//        sl.add(new StudentImplementComparable(10,"许褚",10.0));
        Collections.addAll(sl,
                new StudentImplementComparable(12,"张三",12.3),
                new StudentImplementComparable(15,"李四",33.1),
                new StudentImplementComparable(20,"王五",56.8),
                new StudentImplementComparable(20,"刘备",25.2),
                new StudentImplementComparable(10,"许褚",10.0)
                );

        System.out.println("Comparator接口实现自定义排序");
        //Comparator接口实现自定义排序
        Collections.sort(sl, new Comparator<StudentImplementComparable>() {
            @Override
            public int compare(StudentImplementComparable o1, StudentImplementComparable o2) {
                //年龄升序
                //return o1.getAge() - o2.getAge();
                //年龄降序
                //return o2.getAge() - o1.getAge();
                
                //年龄升序,如果年龄相同则按体重升序排列
                if (o1.getAge() == o2.getAge()){
                    return (int)(o1.getWeight() - o2.getWeight());
                }else{
                    return o1.getAge() - o2.getAge();
                }
            }
        });
        for (StudentImplementComparable s:sl) {
            System.out.println(s);
        }
    }
}

九、遍历集合的四种方式

9.1 方式一:Lambda 表达式遍历集合

public class CollectionEach {
    public static void main(String[] args) {
        //创建一个集合
        Collection books = new HashSet();
        books.add("疯狂原始人");
        books.add("寻梦环游记");
        books.add("时空恋人");
        //调用forEach()方法遍历集合
        books.forEach(obj -> System.out.println("迭代books集合元素:"+obj));
    }
}

9.2 方式二:Iterator 遍历集合

public class IteratorTest {
    public static <Stirng> void main(String[] args) {
        //创建集合、添加元素
        Collection<String> books = new HashSet<>();
        books.add("疯狂原始人");
        books.add("元神");
        books.add("LOL");
        
        //1.获取books集合对应的迭代器
        Iterator it = books.iterator();
        System.out.println(it);//java.util.HashMap$KeyIterator@6d6f6e28
        System.out.println(it.next());//元神
        for (Iterator iter = it; iter.hasNext(); ) {
            String s = (String) iter.next();
            System.out.print(s+",");//疯狂原始人,LOL,
        }
        System.out.println();

        //直接使用next()方法如果集合中没有可迭代的下一个元素将发生异常
        //books.clear();
        //it.next();//java.util.ConcurrentModificationException

        //2.使用hasNext()方法判断books集合中是否还有下一个可迭代的元素
        while (it.hasNext()){
            //3.it.next()方法返回集合里的下一个元素
            //it.next()方法返回的数据类型是Object类型,因此需要进行强制类型转换
            String book = (String)it.next();
            System.out.println("book:"+book);//book:元神 //book:疯狂原始人 //book:LOL
            if (book.equals("元神")){
                //从集合中删除上一次next()方法返回的元素
                it.remove();
            }
            //对book变量赋值,不会改变集合元素本身
            book = "测试字符串";
            System.out.println(book);//测试字符串 //测试字符串 //测试字符串
        }
        System.out.println(books);//[疯狂原始人, LOL]
    }
}

9.3 方式三:Lambda 表达式遍历 Iterator

public class ForEachIteratorTest {
    public static void main(String[] args) {
        //创建集合、添加元素
        Collection<String> books = new HashSet<>();
        books.add("疯狂原始人");
        books.add("元神");
        books.add("LOL");
        
        //获取books集合对应的迭代器
        Iterator it = books.iterator();
        
        //使用Lambda表达式(目标类型是Comsumer)来遍历集合元素
        it.forEachRemaining(obj -> System.out.println("迭代books集合元素:" + obj));
    }
}

在这里插入图片描述

9.4 方式四:foreach 循环遍历集合

public class ForeachCollectionTest {
    public static void main(String[] args) {
        Collection<String> books = new ArrayList<>();
        books.add("java");
        books.add("php");
        books.add("python");
        System.out.println("books有序集合中的元素:"+books);//books有序集合中的元素:[java, php, python]
        
        //foreach遍历books有序集合
        for (String s:books) {
            //此处的s变量不是集合元素本身
            System.out.print(s+",");//java,php,python,
            if (s.equals("python")){
                //下面代码会引发 ConcurrentModificationException 异常
                //集合元素在遍历时不可进行修改!!!【注意】
                //books.remove(s);
            }
        }
        System.out.println();
        System.out.println("books有序集合中的元素:"+books);//books有序集合中的元素:[java, php, python]
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值