集合
7.1 集合概述
为了存储不同类型的多个对象,Java提供了一系列特殊的类,这些类可以存储任意类型的对象,并且存储的长度可变,被统称为集合。集合可以简单理解为一个长度可变,可以存储不同数据类型的动态数组。集合都位于java.util包中,使用集合时必须导入java.util包。
集合体系核心架构图如下所示。
接口 | 描述 |
---|---|
Collection | 集合中最基本的接口,用于存储一组无序、不唯一的对象,一般不直接使用该接口 |
List | Collection的子接口,用于存储一组无序、不唯一的对象,是集合中常用的接口之一 |
Set | Collection的子接口,用于存储一组无序、唯一的对象 |
Map | 用于存储一组键值对象,提供键到值的映射 |
7.2 Collection接口
Collection接口是Java单列集合中的根接口,它定义了各种具体单列集合的共性,其他
单列集合大多直接或间接继承该接口,Collection接口的定义如下所示:
public interface Collection<E> extends Iterable<E>{
//Query Operations
}
方法声明 | 功能描述 |
---|---|
boolean add(Object o) | 向集合中添加一个元素 |
boolean addAll(Collection c) | 将指定集合c中的所有元素添加到本集合中 |
void clear() | 删除集合中的所有元素 |
boolean remove(Object o) | 删除集合中指定的元素 |
boolean removeAll(Collection c) | 删除当前集合中包含集合c中的所有元素 |
方法声明 | 功能描述 |
---|---|
boolean isEmpty() | 判断集合是否为空 |
boolean contains(Object o) | 判断集合中是否包含某个元素 |
boolean containsAll(Collection c) | 判断集合中是否包含指定集合c中的所有元素 |
Iterator iterator() | 返回集合的的迭代器(Iterator),迭代器用于遍历该集合所有元素 |
int size() | 获取集合元素个数 |
7.3 List接口
List接口继承自Collection接口,List接口实例中允许存储重复的元素,所有的元素以线性方式进行存储。在程序中可以通过索引访问List接口实例中存储的元素。另外,List接口实例中存储的元素是有序的,即元素的存入顺序和取出顺序一致。
7.3.1 List接口简介
方法声明 | 功能描述 |
---|---|
void add(int index,Object element) | 将元素element插入List的index索引处 |
boolean addAll(int index,Collection c) | 将集合c所包含的所有元素插入到List集合的index索引处 |
Object get(int index) | 返回集合index索引处的元素 |
Object remove(int index) | 删除index索引处的元素 |
Object set(int index, Object element) | 将index索引处元素替换成element对象,并将替换后的元素返回 |
int indexOf(Object o) | 返回对象o在List中第一次出现的位置索引 |
int lastIndexOf(Object o) | 返回对象o在List中最后一次出现的位置索引 |
List subList (int fromIndex, int toIndex) | 返回从索引fromIndex(包括)到 toIndex(不包括)处所有元素集合组成的子集合 |
7.3.1 ArrayList
ArrayList是List接口的一个实现类,它是程序中最常见的一种集合。ArrayList集合内部封装了一个长度可变的数组对象,当存入的元素超过数组长度时,ArrayList会在内存中分配一个更大的数组来存储这些元素,因此可以将ArrayList集合看作一个长度可变的数组。
import java.util.ArrayList;
public class Example02 {
public static void main(String[] args){
ArrayList list=new ArrayList();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
list.add("zhaoliu");
System.out.println("集合的长度:"+list.size());
System.out.println("第二个元素是:"+list.get(1));
list.remove(3); // 删除索引为3的元素
System.out.println("删除索引为3的元素:"+list);
list.set(1,"sili2");
System.out.println("替换索引为1的元素为lisi2:"+list);
}
}
由于ArrayList集合的底层是使用一个数组来存储元素,在增加或删除指定位置的元素时,会创建新的数组,效率比较低,因此Arraylist集合不适合做大量的增删操作,而适合元素的查找。
7.3.3 LinkedList
为了克服ArrayList集合在查询元素时速度很快,但在增删元素时效率较低的局限性,可以使用List接口的另一个实现类LinkedList。LinkedList集合内部维护了一个双向循环链表,链表中的每一个元素都使用引用的方式记录它的前一个元素和后一个元素,从而可以将所有的元素彼此连接起来。当插入一个新元素时,只需要修改元素之间的引用关系即可,删除一个节点也是如此。正因为这样的存储结构,所以LinkedList集合增删效率非常高。
方法声明 | 功能描述 |
---|---|
void add(int index, E element) | 在集合的index索引处插入element元素 |
void addFirst(Object o) | 将指定元素o插入此集合的开头 |
void addLast(Object o) | 将指定元素o添加到此集合的结尾 |
Object getFirst() | 返回此集合的第一个元素 |
Object getLast() | 返回此集合的最后一个元素 |
Object removeFirst() | 移除并返回集合的第一个元素 |
Object removeLast() | 移除并返回集合的最后一个元素 |
boolean offer(Object o) | 将指定元素o添加到集合的结尾 |
boolean offerFirst(Object o) | 将指定元素o添加到集合的开头 |
boolean offerLast(Object o) | 将指定元素o添加到集合的结尾 |
Object peekFirst() | 获取集合的第一个元素 |
Object peekLast() | 获取集合的最后一个元素 |
Object pollFirst() | 移除并返回集合的第一个元素 |
Object pollLast() | 移除并返回集合的最后一个元素 |
void push(Object o) | 将指定元素o添加到集合的开头 |
import java.util.LinkedList;
public class Example02 {
public static void main(String[] args){
LinkedList link=new LinkedList();
link.add("zhangsan");
link.add("lisi");
link.add("wangwu");
link.add("zhaoliu");
System.out.println(link.toString());
link.add(3,"Student"); //索引3处加入Student
link.addFirst("First"); //第一个位置加入First
System.out.println(link);
System.out.println(link.getFirst()); //取出来第一个元素
link.remove(3);
link.removeFirst();
System.out.println(link);
}
}
7.4 集合遍历
7.4.1 Iterator接口
Iterator接口是Java集合框架中的一员,但它与Collection、Map接口有所不同,Collection接口与Map接口主要用于存储元素,而Iterator主要用于迭代访问(遍历)Collection中的元素,通常情况下Iterator对象也被称为迭代器。
import java.util.ArrayList;
import java.util.Iterator;
public class Example02 {
public static void main(String[] args){
ArrayList list=new ArrayList();
list.add("张三"); // 向该集合中添加字符串
list.add("李四");
list.add("王五");
list.add("赵六");
Iterator it = list.iterator();
while(it.hasNext()){
Object obj=it.next();
System.out.println(obj);
}
}
}
迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的
元素。迭代器迭代元素过程如下图所示。
在使用Iterator迭代器对集合中的元素进行迭代时,如果调用了集合对象的remove()方法删除元素,之后继续使用迭代器遍历元素,会出现异常。
解决方案1:
if ("张三".equals(obj)) {
list.remove(obj);
break;
}
解决方案2:
if ("张三".equals(obj)) {
it.remove();
}
7.4.2 foreach循环
import java.util.ArrayList;
public class Example02 {
public static void main(String[] args){
ArrayList list=new ArrayList();
list.add("张三"); // 向ArrayList集合中添加字符串元素
list.add("李四");
list.add("王五");
for(Object obj:list){
System.out.println(obj);
}
}
}
foreach循环虽然书写起来很简洁,但在使用时也存在一定的局限性。当使用foreach循环遍历集合和数组时,只能访问集合中的元素,不能对其中的元素进行修改。
public class Example02 {
static String[] strs = {"aaa", "bbb", "ccc"};
public static void main(String[] args) {
//foreach
for (String str : strs) {
str = "ddd";
}
System.out.println("foreach循环修改后的数组:" + strs[0] + "," + strs[1] + "," + strs[2]);
//for
for (int i = 0; i < strs.length; i++) {
strs[i] = "ddd";
}
System.out.println("普通for循环修改后的数组:" + strs[0] + "," + strs[1] + "," + strs[2]);
}
}
7.5 Set接口
7.5.1 Set接口简介
Set接口也继承自Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充。与List接口不同的是,Set接口中元素是无序的,并且都会以某种规则保证存入的元素不出现重复。
Set接口常见的实现类有3个,分别是HashSet、LinkedHashSet、TreeSet。其中,
HashSet
根据对象的哈希值来确定元素在集合中的存储位置,具有良好的存取和查找性能;
LinkedHashSet
是链表和哈希表组合的一个数据存储结构;
TreeSet
则是以二叉树的方式存储元素,它可以对集合中的元素进行排序。
7.5.2 HashSet
HashSet是Set接口的一个实现类,它所存储的元素是不可重复的。当向HashSet集合中添加一个元素时,首先会调用该元素的hashCode()方法来确定元素的存储位置,然后再调用元素对象的equals()方法来确保该位置没有重复元素。Set集合与List集合存取元素的方式都一样,但是Set集合中的元素是无序的。
import java.util.HashSet;
import java.util.Iterator;
public class Example02 {
public static void main(String[] args){
HashSet hset=new HashSet();
hset.add("张三"); // 向该Set集合中添加字符串
hset.add("李四");
hset.add("王五");
hset.add("李四"); // 向该Set集合中添加重复元素
Iterator it=hset.iterator(); //获取Iterator对象
while(it.hasNext()){
Object obj=it.next();
System.out.println(obj);
}
}
}
由上图的打印结果可以看出,取出元素的顺序与添加元素的顺序并不一致,并且重复存入的字符串对象“李四”被去除了,只添加了一次。
当调用HashSet集合的add()方法存入元素时,首先调用HashSet集合的hashCode()方法获得元素对象的哈希值,然后根据对象的哈希值计算出一个存储位置。如果该位置上没有元素,则直接将元素存入。如果该位置上有元素存在,则会调用equals()方法让当前存入的元素和该位置上的元素进行比较,如果返回的结果为false,就将该元素存入集合,返回的结果为true,则说明有重复元素,就将需要存入的重复元素舍弃。
import java.util.HashSet;
class Student {
String id;
String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
public String toString() {
return id + ":" + name;
}
}
public class Example02 {
public static void main(String[] args) {
HashSet hs = new HashSet();
Student stu1 = new Student("1", "张三");
Student stu2 = new Student("2", "李四");
Student stu3 = new Student("2", "李四");
hs.add(stu1);
hs.add(stu2);
hs.add(stu3);
System.out.println(hs);
}
}
由上图可知,运行结果中出现了两个相同的学生信息“2:李四”,这样的学生信息应该被视为重复元素,不允许同时出现在HashSet集合中。上面文件之所以没有去掉这样的重复元素,是因为在定义Student类时没有重写hashCode()和equals()方法。
向HashSet集合中添加数据时去除重复数据
import java.util.HashSet;
class Student {
String id;
String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
public String toString() {
return id + ":" + name;
}
//重写hashCode()方法
public int hashCode() {
return id.hashCode(); //返回id属性的哈希值
}
//重写equals()方法
public boolean equals(Object obj) {
if (this == obj) // 判断是否是同一个对象
return true;
if (!(obj instanceof Student)) { //判断对象是Student类型
return false;
}
Student stu = (Student) obj; //将对象类型转为Student
boolean b = this.id.equals(stu.id); //判断id值是否相同
return b;
}
}
public class Example02 {
public static void main(String[] args) {
HashSet hs = new HashSet();
Student stu1 = new Student("1", "张三");
Student stu2 = new Student("2", "李四");
Student stu3 = new Student("2", "李四");
hs.add(stu1);
hs.add(stu2);
hs.add(stu3);
System.out.println(hs);
}
}
7.5.3 LinkedHashSet
HashSet集合存储的元素是无序的,如果想让元素的存取顺序一致,可以使用Java提供的LinkedHashSet类,LinkedHashSet类是HashSet的子类,与LinkedList一样,它也使用双向链表来维护内部元素的关系。
import java.util.Iterator;
import java.util.LinkedHashSet;
public class Example02 {
public static void main(String[] args) {
LinkedHashSet set = new LinkedHashSet();
set.add("张三"); // 向该Set集合中添加字符串
set.add("李四");
set.add("王五");
Iterator it = set.iterator(); // 获取Iterator对象
while (it.hasNext()) { // 通过while循环,判断集合中是否有元素
Object obj = it.next();
System.out.println(obj);
}
}
}
7.5.4 TreeSet
TreeSet是Set接口的另一个实现类,它内部采用平衡二叉树来存储元素,这样的结构可以保证TreeSet集合中没有重复的元素,并且可以对元素进行排序。所谓二叉树就是说每个节点最多有两个子节点的有序树,每个节点及其子节点组成的树称为子树,通常左侧的子节点称为“左子树”,右侧的节点称为“右子树”,其中左子树上的元素小于它的根结点,而右子树上的元素大于它的根结点。
在二叉树中,同一层的元素,左边的元素总是小于右边的元素。接下来通过一个具体的图例来演示二叉树的存储过程。
假设向集合中存入8个元素,依次为13、8、17、17、1、11、15、25,如果以二叉树的方式来存储,在集合中的存储结构会形成一个树状结构。具体存储方式如下图所示。
方法声明 | 功能描述 |
---|---|
Object first() | 返回TreeSet集合的首个元素 |
Object last() | 返回TreeSet集合的最后一个元素 |
Object lower(Object o) | 返回TreeSet集合中小于给定元素的最大元素,如果没有返回null |
Object floor(Object o) | 返回TreeSet集合中小于或等于给定元素的最大元素,如果没有返回null |
Object higher(Object o) | 返回TreeSet集合中大于给定元素的最小元素,如果没有返回null |
Object ceiling(Object o) | 返回TreeSet集合中大于或等于给定元素的最小元素,如果没有返回null |
Object pollFirst() | 移除并返回集合的第一个元素 |
Object pollLast() | 移除并返回集合的最后一个元素 |
import java.util.TreeSet;
public class Example02 {
public static void main(String[] args) {
// 创建TreeSet集合
TreeSet ts = new TreeSet();
// 1、向TreeSet集合中添加元素
ts.add(3);
ts.add(29);
ts.add(101);
ts.add(21);
System.out.println("创建的TreeSet集合为:" + ts);
// 2、获取首尾元素
System.out.println("TreeSet集合首元素为:" + ts.first());
System.out.println("TreeSet集合尾部元素为:" + ts.last());
// 3、比较并获取元素
System.out.println("集合中小于或等于9的最大的一个元素为:" + ts.floor(9));
System.out.println("集合中大于10的最小的一个元素为:" + ts.higher(10));
System.out.println("集合中大于100的最小的一个元素为:" + ts.higher(100));
// 4、删除元素
Object first = ts.pollFirst();
System.out.println("删除的第一个元素是:" + first);
System.out.println("删除第一个元素后TreeSet集合变为:" + ts);
}
}
Java提供了两种TreeSet的排序规则,分别为自然排序和自定义排序。在默认情况下,TreeSet集合都是采用自然排序,接下来将对这两种排序规则进行详细讲解。
自然排序要求向TreeSet集合中存储的元素所在类必须实现Comparable接口,并重写compareTo()方法,然后TreeSet集合就会对该类型元素使用compareTo()方法进行比较。compareTo()方法将当前对象与指定的对象进行顺序比较,返回值为一个整数,其中返回负整数、零或正整数分别表示当前对象小于、等于或大于指定对象,默认根据比较结果顺序排列。
compareTo()方法实现对象元素的顺序存取
import java.util.TreeSet;
//定义Student类并实现Comparable接口,声明属性name和age,
// 重写toString()方法,
// 重写Comparable接口的compareTo()方法。
class Student implements Comparable {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return name + ":" + age;
}
public int compareTo(Object obj) {
Student stu = (Student) obj;
//定义比较方式,先比较age,再比较name
if (this.age > stu.age) {
return 1;
}
if (this.age == stu.age) {
return this.name.compareTo(stu.name);
}
return -1;
}
}
public class Example02 {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add(new Student("Lucy", 18));
ts.add(new Student("Tom", 20));
ts.add(new Student("Bob", 20));
ts.add(new Student("Tom", 20));
System.out.println(ts);
}
}
自定义排序
如果不想实现Comparable接口或者不想按照实现了Comparable接口的类中compareTo()方法的规则进行排序,可以通过自定义比较器的方式对TreeSet集合中的元素自定义排序规则。实现Comparator接口的类都是一个自定义比较器,可以在自定义比较器中的compare()方法中自定义排序规则。
7.6 Map接口
7.6.1 Map接口简介
Map接口是一种双列集合,它的每个元素都包含一个键对象Key和值对象Value,键和值对象之间存在一种对应关系,称为映射。Map中键对象Key不允许重复,访问Map集合中的元素时,只要指定了Key,就能找到对应的Value。
方法声明 | 功能描述 |
---|---|
void put(Object key, Object value) | 将指定的值和键存入到集合中,并进行映射关联 |
Object get(Object key) | 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回null |
void clear() | 移除所有的键值对元素 |
V remove(Object key) | 根据键删除对应的值,返回被删除的值 |
int size() | 返回集合中的键值对的个数 |
boolean containsKey(Object key) | 如果此映射包含指定键的映射关系,则返回 true。 |
boolean containsValue(Object value) | 如果此映射将一个或多个键映射到指定值,则返回 true |
Set keySet() | 返回此映射中包含的键的Set集合 |
Collection values() | 返回此映射中包含的值的Collection集合 |
Set<Map.Entry<K,V>>entrySet() | 返回此映射中包含的映射关系的Set集合 |
import java.util.HashMap;
import java.util.Map;
public class Example02 {
public static void main(String[] args) {
Map map = new HashMap(); // 创建HashMap对象
map.put("1", "张三"); // 存储键和值
map.put("2", "李四");
map.put("3", "王五");
System.out.println("1:" + map.get("1")); // 根据键获取值
System.out.println("2:" + map.get("2"));
System.out.println("3:" + map.get("3"));
}
}
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
//先获取集合中所有的映射关系,然后从映射关系中取出键和值。
public class Example02 {
public static void main(String[] args) {
Map map = new HashMap(); // 创建HashMap集合
map.put("1", "张三"); // 存储键和值
map.put("2", "李四");
map.put("3", "王五");
Set entrySet = map.entrySet();
Iterator it = entrySet.iterator(); // 获取Iterator对象
while (it.hasNext()) {
// 获取集合中键值对映射关系
Map.Entry entry = (Map.Entry) (it.next());
Object key = entry.getKey(); // 获取Entry中的键
Object value = entry.getValue(); // 获取Entry中的值
System.out.println(key + ":" + value);
}
}
}
Map还提供了一些操作集合的常用方法,例如,values()方法用于获取map实例中所有的value,返回值类型为Collection;size()方法获取map集合的大小;containsKey()方法用于判断是否包含传入的键;containsValue()方法用于判断是否包含传入的值;remove()方法用于根据key移除map中的与该key对应的value等。
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class Example02 {
public static void main(String[] args) {
Map map = new HashMap(); // 创建HashMap集合
map.put("1", "张三"); // 存储键和值
map.put("3", "李四");
map.put("2", "王五");
map.put("4", "赵六");
System.out.println("集合大小为:"+map.size());
System.out.println("判断是否包含传入的键(2):"+map.containsKey("2"));
System.out.println("判断是否包含传入的值(王五):"+map.containsValue("王五"));
System.out.println("移除键为1的值是:"+map.remove("1"));
Collection values = map.values();
Iterator it = values.iterator();
while (it.hasNext()) {
Object value = it.next();
System.out.println(value);
}
}
}
7.6.3 LinkedHashMap
HashMap集合迭代出来元素的顺序和存入的顺序是不一致的。如果想让这Map集合中的元素迭代顺序与存入顺序一致,可以使用LinkedHashMap集合,LinkedHashMap是HashMap的子类,与LinkedList一样,LinkedHashMap集合也使用双向链表维护内部元素的关系,使Map集合元素迭代顺序与存入顺序一致。
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
public class Example02 {
public static void main(String[] args) {
Map map = new LinkedHashMap(); //创建LinkedHashMap集合
map.put("3", "李四"); // 存储键和值
map.put("2", "王五");
map.put("4", "赵六");
Set keySet=map.keySet();
Iterator it=keySet.iterator();
while(it.hasNext()){
Object key=it.next();
Object value=map.get(key); //获取每个键所对应的值
System.out.println(key+":"+value);
}
}
}
7.6.4 TreeMap
HashMap集合存储的元素的键值是无序的和不可重复的,为了对集合中的元素的键值进行排序,Map接口还有了另一个可以对集合中元素键和值进行排序的实现类TreeMap。
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class Example02 {
public static void main(String[] args) {
Map map = new TreeMap(); // 创建TreeMap集合
map.put(3, "李四"); // 存储键和值
map.put(2, "王五");
map.put(4, "赵六");
map.put(3, "张三");
Set keySet = map.keySet();
Iterator it = keySet.iterator();
while (it.hasNext()) {
Object key = it.next();
Object value = map.get(key); // 获取每个键所对应的值
System.out.println(key+":"+value);
}
}
}
由上图可知,添加的元素已经按键值从小到大进行自动排序,并且键值重复存入的整数3只有一个,只是后来添加的值“张三”覆盖了原来的值“李四”。这也证实了TreeMap中的键必须是唯一的,不能重复并且有序,如果存储了相同的键,后存储的值则会覆盖原有的值。
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
class Student {
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = 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;
}
@Override
public String toString() {
return "Student [name" + name + ", age=" + age + ']';
}
}
public class Example02 {
public static void main(String[] args) {
TreeMap tm = new TreeMap(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getName().compareTo(s2.getName());//按照姓名比较
return num == 0 ? num:s1.getAge() - s2.getAge();
}
});
tm.put(new Student("张三", 23), "北京");
tm.put(new Student("李四", 13), "上海");
tm.put(new Student("赵六", 43), "深圳");
tm.put(new Student("王五", 33), "广州");
Set keySet=tm.keySet();
Iterator it=keySet.iterator();
while(it.hasNext()){
Object key=it.next();
Object value=tm.get(key); //获取每个键所对应的值
System.out.println(key+":"+value);
}
}
}
7.6.5 Properties
Map接口还有一个实现类Hashtable,它和HashMap十分相似,区别在于Hashtable是线程安全的。Hashtable存取元素时速度很慢,目前基本上被HashMap类所取代。但Hashtable类有一个很重要的子类Properties,应用非常广泛。Properties主要用于存储字符串类型的键和值,在实际开发中,经常使用Properties集合存储应用的配置项。
import java.util.Enumeration;
import java.util.Properties;
public class Example02 {
public static void main(String[] args){
Properties p=new Properties(); //创建Properties对象
p.setProperty("Backgroup-color", "red");
p.setProperty("Font-size", "14px");
p.setProperty("Language", "chinese");
Enumeration names = p.propertyNames(); //获取Enumeration对象所有键枚举
while(names.hasMoreElements()){ //循环遍历所有的键
String key=(String)names.nextElement();
String value=p.getProperty(key); //获取对应键的值
System.out.println("key="+key+" value="+value);
}
}
}
7.7 常用工具类
1 添加、排序操作
方法声明 | 功能描述 |
---|---|
static boolean addAll(Collection<? super T> c, T… elements) | 将所有指定元素添加到指定集合c中 |
static void reverse(List list) | 反转指定List集合中元素的顺序 |
static void shuffle(List list) | 随机打乱List集合中元素的顺序 |
static void sort(List list) | 根据元素的自然顺序(从小到大)对List集合中的元素进行排序 |
static void swap(List list,int i,int j) | 将指定List集合中索引为i的元素和索引为j的元素进行交换 |
import java.util.ArrayList;
import java.util.Collections;
public class Example02 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "C", "Z", "B", "K"); // 添加元素
System.out.println("排序前:" + list);
Collections.reverse(list);
System.out.println("反转后:" + list);
Collections.sort(list);
System.out.println("按自然顺序排序后: " + list);
Collections.shuffle(list); // 随机打乱集合元素
System.out.println("按随机顺序排序后: " + list);
Collections.swap(list, 0, list.size() - 1);// 将集合首尾元素交换
System.out.println("集合首尾元素交换后: " + list);
}
}
2 查找、替换操作
方法声明 | 功能描述 |
---|---|
static int binarySearch(List list,Object key) | 使用二分法搜索指定对象在List集合中的索引,要求查找的List集合中的元素必须是有序的 |
static Object max(Collection col) | 根据元素的自然顺序,返回给定集合中最大的元素 |
static Object min(Collection col) | 根据元素的自然顺序,返回给定集合中最小的元素 |
static boolean replaceAll(List list,Object oldVal,Object newVal) | 用一个新值newVal替换List集合中所有的旧值oldVal |
import java.util.ArrayList;
import java.util.Collections;
public class Example02{
public static void main(String[] args){
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list,-3,2,9,5,8);
System.out.println("集合中的元素:"+list);
System.out.println("集合中的最大元素: " + Collections.max(list));
System.out.println("集合中的最小元素: " + Collections.min(list));
Collections.replaceAll(list, 8, 0); // 将集合中的8用0替换掉
System.out.println("替换后的集合: " + list);
Collections.sort(list); //使用二分查找前,必须保证元素有序
System.out.println("集合排序后为: "+list);
int index = Collections.binarySearch(list, 9);
System.out.println("集合通过二分查找方法查找元素9所在索引为:"+index);
}
}
7.7.2 Arrays工具类
import java.util.Arrays;
public class Example02 {
public static void main(String[] args) {
int[] arr = {9, 8, 3, 5, 2}; // 初始化一个数组
System.out.print("排序前:");
printArray(arr); // 打印原数组
Arrays.sort(arr); // 调用Arrays的sort()方法排序
System.out.print("排序后:");
printArray(arr); // 打印排序后数组
}
// 定义打印数组元素方法
public static void printArray(int[] arr) {
System.out.print("[");
for (int x = 0; x < arr.length; x++) {
if (x != arr.length - 1) {
System.out.print(arr[x] + ", ");
} else {
System.out.println(arr[x] + "]");
}
}
}
}
由上图可知,使用Arrays的sort()方法时将会按照自然顺序对数组元素进行从小到大排序,使用非常方便。针对数组排序,数组工具类Arrays还提供了其他多个重载的sort()方法,既可以按照自然顺序进行排序,也可以传入比较器参数按照定制规则排序,同时还支持选择排序的元素范围。
在程序开发中,经常会在数组中查找某些特定的元素,如果数组中元素较多时查找某个元素,效率会非常低。为此,Arrays工具类中提供了一个binarySearch()方法用于查找元素。binarySearch()方法声明如下所示。
binarySearch(Object[] a, Object key);
//在上述语法中,参数a是指被查询的集合,参数key指被查询的元素值。
import java.util.Arrays;
public class Example02 {
public static void main(String[] args) {
int[] arr = { 9, 8, 3, 5, 2 };
Arrays.sort(arr); // 对数组进行排序
int index = Arrays.binarySearch(arr, 3); // 查找指定元素3
System.out.println("元素3的索引是:" + index);
}
}
3 使用copyOfRange()方法复制元素
在程序开发中,经常需要在不破坏原数组的情况下使用数组中的部分元素,这时可以使用Arrays工具类的copyOfRange()方法,copyOfRange()方法可以将数组中指定范围的元素复制到一个新的数组中。copyOfRange()方法声明格式如下所示。
copyOfRange(int[] original, int from,int to);
在上述语法中,参数original表示被复制的数组,from表示被复制元素的初始索引(包括),to表示被复制元素的最后索引(不包括)。
import java.util.Arrays;
public class Example02 {
public static void main(String[] args) {
int[] arr = { 9, 8, 3, 5, 2 };
// 复制一个指定范围的数组
int[] copied = Arrays.copyOfRange(arr, 1, 7);
for (int i = 0; i < copied.length; i++) {
System.out.print(copied[i] + " ");
}
}
}
4 使用fill()方法替换元素
程序开发中,可能会需要将一个数组中的所有元素替换成同一个元素,此时可以使用Arrays工具类的fill()方法,该方法可以将指定的值赋给数组中的每一个元素,fill()方法声明如下所示。
fill(Object[] a,Object val);
在上述语法中,参数a表示被修改的数组,val表示需要被替换成的元素。
import java.util.Arrays;
public class Example02 {
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4 };
Arrays.fill(arr, 8); // 用8替换数组中的每个元素
for (int i = 0; i < arr.length; i++) {
System.out.println(i + ": " + arr[i]);
}
}
}
7.8 Lambda表达式
语法格式 | 描述 |
---|---|
()-> System.out.println(“Hello Lambda!”); | 无参数,无返回值 |
(x) -> System.out.println(x) | 有一个参数,并且无返回值 |
x -> System.out.println(x) | 若只有一个参数,小括号可以省略不写 |
Comparator com = (x, y) -> { System.out.println(“函数式接口”); return Integer.compare(x, y); }; | 有两个以上的参数,有返回值,并且 Lambda 方法体中有多条语句 |
Comparator com = (x, y) -> Integer.compare(x, y); | 若Lambda 体中只有一条语句,return 和大括号都可以省略不写 |
(Integer x, Integer y) -> Integer.compare(x, y); | Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断” |
import java.util.Arrays;
public class Example02 {
public static void main(String[] args) {
String[] arr = {"program", "creek", "is", "a", "java", "site"};
Arrays.sort(arr, (m, n) -> Integer.compare(m.length(), n.length()));
System.out.println("Lambda语句体中只有一条语句,参数类型可推断:"+
Arrays.toString(arr));
Arrays.sort(arr, (String m, String n) -> {
if (m.length() > n.length())
return -1;
else
return 0;
});
System.out.println("Lambda语句体中有多条语句:"+Arrays.toString(arr));
}
}
首先介绍了集合的概念和Collection接口;
其次介绍了List接口,包括ArrayList集合、LinkedList集合、Iterator迭代器和foreach循环;
接着介绍了Set接口,包括HashSet集合、LinkedHashSet集合和TreeSet集合;
然后介绍了Map接口,包括HashMap集合、LinkedHashMap集合、TreeMap集合和Properties集合;
接着又介绍了集合的常用工具类,包括Collections工具类和Arrays工具类;
最后介绍了Lambda表达式。