Java知识点04——集合(Set、List、Queue、Map、Collection、Iterator、Collections工具类)
声明:
- 该资料来自自己整理。
- 参考书籍
疯狂 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:
- 使用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)对象中的键与值。
操作步骤与图解:
- 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。方法提示:
Ojbect.entrySet()
。 - 遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象。
- 通过键值对(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.Iterator
。Iterator
接口也是Java集合中的一员,但它与Collection
、Map
接口有所不同,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
- 在进行集合元素取出时,如果集合中已经没有元素了,还继续使用迭代器的next方法,将会发生java.util.ConcurrentModificationException并发异常。
- 当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
迭代器的实现原理
当遍历集合时,首先通过调用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]
}
}