集合分类及打印的方式
集合分类
在 Java 中,集合(Collections)是一个用于存储和操作数据结构的框架。它为各种数据结构(如列表、集、映射等)提供了标准的操作方法。Java 的集合框架被设计得非常灵活和强大,主要分类为三大类:List(列表)、Set(集合)和 Map(映射)。这些接口和类位于 java.util
包中。
- List:有序,允许重复。
- Set:无序,不允许重复。
- Map:键值对,键不重复,值可重复。
- Queue:先进先出,适合任务调度。
1. List(列表)
- 特点:允许存储重复的元素,元素是有序的,意味着元素有插入顺序。
- 常用实现类:
-
- ArrayList:基于数组实现,支持快速随机访问,但在数组大小动态调整时性能较低。
- LinkedList:基于双向链表实现,适合频繁的插入和删除操作,随机访问速度较慢。
- Vector:类似于 ArrayList,但它是线程安全的(同步的),通常效率较低。
- 例子:
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Apple"); // 可以存储重复的元素
2. Set(集合)
- 特点:不允许存储重复的元素,元素是无序的,意味着没有固定的插入顺序。
- 常用实现类:
-
- HashSet:基于哈希表实现,元素无序,插入和查找的速度很快。
- LinkedHashSet:与 HashSet 类似,但保持插入顺序。
- TreeSet:基于红黑树实现,元素有序(自然排序或自定义比较器),适合需要排序的场景。
- 例子:
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Apple"); // 重复元素不会被加入
3. Map(映射)
- 特点:存储键值对(key-value pair),键不允许重复,但值可以重复。
- 常用实现类:
-
- HashMap:基于哈希表实现,键值对无序,插入和查找速度快。
- LinkedHashMap:类似于 HashMap,但保持插入顺序。
- TreeMap:基于红黑树实现,按键的自然排序或自定义比较器排序。
- Hashtable:线程安全的实现,效率较低,不允许
null
键或null
值。
- 例子:
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 1);
map.put("Banana", 2);
map.put("Apple", 3); // 覆盖原来的键 "Apple"
4. Queue(队列)
- 特点:按先进先出(FIFO)顺序存储元素,适合任务调度等场景。
- 常用实现类:
-
- LinkedList:不仅实现了 List,还实现了 Queue,支持队列操作。
- PriorityQueue:基于堆实现,元素按优先级排序,非 FIFO 顺序。
- 例子:
Queue<String> queue = new LinkedList<>();
queue.add("Apple");
queue.add("Banana");
queue.poll(); // 移除并返回第一个元素
集合框架中的接口关系
Java 集合框架中的各个接口及其实现类关系非常紧密。可以总结为:
- Collection 是根接口,
List
和Set
是其子接口。 - Map 独立于
Collection
接口,但也是集合框架的重要组成部分。
循环方式
传统for
循环
最基础的方式,通过索引值遍历集合(适用于List
)。
for (int i = 0; i < list.size(); i++) {
SmbmsUser user = list.get(i);
System.out.println(user);
}
- 优点:可控制遍历的起始和步长,适用于需要访问元素的索引的场景。
- 缺点:不适合遍历
Set
和其他无索引的集合。
2.增强型for
循环(foreach循环)
简化版本的for
循环,无需手动控制索引,适用于任何Iterable
集合。
for (SmbmsUser user : list) {
System.out.println(user);
}
SmbmsUser: 这是集合list中的元素类型,明显SmbmsUser类型的对象。
user这是:循环中的临时标志名称,用于货架每次迭代list时取出的SmbmsUser对象。你可以把它改成其他名称,比如user,代码仍然可以工作。
list这是:一个List类型的集合,里面存储了多个SmbmsUser对象。list是集合名。
每个循环都会从list集合中取出一个SmbmsUser对象,赋予临时变量SmbmsUser,然后执行循环里面的操作。
- 优点:简单插入,不需要索引操作。
- 缺点:无法在探索过程中集合(如删除元素)。
3. 使用Iterator
(适合复杂操作,如删除元素)
使用Iterator
来遍历集合,适合在遍历时修改集合。
Iterator<SmbmsUser> iterator = list.iterator();
while (iterator.hasNext()) {
SmbmsUser user = iterator.next();
System.out.println(user);
}
什么是Iterator?
Iterator是一个接口,用于遍历集合元素的通用方式。它提供了一种方法来顺序访问集合中的元素,而不需要引用集合的底层实现。
使用Iterator步骤:
获取Iterator对象:通过集合的iterator()方法获取一个Iterator对象。
使用hasNext()方法:判断集合中是否还有下一个元素。
使用next()方法:获取集合中的下一个元素。
使用remove()方法(任选):在遍历过程中删除当前元素。
使用Iterator
它的好处是可以在遍历时安全地删除集合中的元素,而不引发ConcurrentModificationException
异常,这是在使用传统for
循环时容易遇到的问题。另外,Iterator
提供了一种统一的遍历方式,适用于各个种类型的集合。
Java案例
假设有一个List<SmbmsUser>
集合,下面是使用Iterator
遍历并打印每个用户的代码:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
class SmbmsUser {
private String username;
private String password;
public SmbmsUser(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public String toString() {
return "用户名:" + username + ",密码:" + password;
}
}
public class IteratorExample {
public static void main(String[] args) {
//创建List集合
List<SmbmsUser> list = new ArrayList<>();
list.add(new SmbmsUser("user1", "pass1"));
list.add(new SmbmsUser("user2", "pass2"));
list.add(new SmbmsUser("user3", "pass3"));
// 使用 Iterator 遍历
Iterator<SmbmsUser> iterator = list.iterator();
while (iterator.hasNext()) {
SmbmsUser user = iterator.next();
System.out.println(user);
// 示例:条件删除 选出 user2进行删除
if ("user2".equals(user.username)) {
iterator.remove(); // 从集合中删除当前元素
}
}
System.out.println("遍历后剩余用户:");
for (SmbmsUser user : list) {
System.out.println(user);
}
}
}
- 优点:可以在航行时安全地修改集合(如删除元素)。
- 缺点:需要更多的代码,语法相对繁琐。
- 使用
Iterator
它的好处是可以在遍历时安全地删除集合中的元素,而不引发ConcurrentModificationException
异常,这是在使用传统for
循环时容易遇到的问题。另外,Iterator
提供了一种统一的遍历方式,适用于各个种类型的集合。
4. 使用ListIterator
ListIterator
是Iterator
的扩展,专门用于List
,可以遍历,并支持在遍历中修改集合。
ListIterator<SmbmsUser> listIterator = list.listIterator();
while (listIterator.hasNext()) {
SmbmsUser user = listIterator.next();
System.out.println(user);
// 可以在遍历时添加元素
if ("user2".equals(user.getUsername())) {
listIterator.add(new SmbmsUser("newUser", "newPass"));
}
}
- 优点:支持用户(通过
hasPrevious()
和previous()
),在修改中添加、删除或元素。 - 缺点:只能用于
List
类型的集合。
5. 使用 Java 8 的forEach
方法
Java 8 引入了forEach
方法,通过 Lambda 表达式遍历集合,写法更简洁。
list.forEach(user -> System.out.println(user));
1. list.forEach()
:
forEach
是List
接口的一种方法,用于遍历集合中的各个元素。- 当你调用
list.forEach()
时,系统会自动循环处理list
中的每个元素,类似于传统的for
循环。
2. user -> System.out.println(user)
:
- 这是一个Lambda 表达式,表示如何处理集合中的每个元素。
user
:这是list
中的当前元素。forEach
每次从list
那里取出一个元素并提交给user
。->
:表示“接下来要做的操作”。System.out.println(user)
:这是要对每个元素执行的操作,然后打印出当前的user
。
6. 使用 Java 8 的Stream
API
Stream
API是Java 8引入的功能,提供了链式操作集合的方式,特别适合处理复杂的数据流操作。
list.stream().forEach(user -> System.out.println(user));
list.stream()
:
- 作用:将
List
转换为Stream
对象。 - Stream是一个表示元素序列的抽象概念,可以对这些元素进行各种处理(如过滤、排序、映射等)。
- 特点:
-
- 指定求值:许多操作会延迟执行,直到最终需要结果时才会执行。
- 可处理大量数据:Stream 高效处理大数据集,可以支持工件处理。
forEach(...)
:
- 作用:对
Stream
中每个元素执行指定的操作。 forEach
方法是一个终止操作,意味着它会触发流程的处理并遍历所有元素。- 特点:无法再
Stream
进行后续操作,因为forEach
已经消耗了流量。
示例:
stream.forEach(user -> System.out.println(user));
user -> System.out.println(user)
:
- 这是一个Lambda 表达式,用于定义
forEach
方法中的操作。 user
:表示流中的当前元素(list
即取出的每个用户)。->
:用于分隔参数和执行的操作部分。System.out.println(user)
:对于每个元素,打印出当前的user
对象。
7. 使用do-while
循环
do-while
循环保证循环体至少执行一次,适用于某些特殊逻辑需要。
int i = 0;
do {
SmbmsUser user = list.get(i);
System.out.println(user);
i++;
} while (i < list.size());
- 优点:在某些情况下,能够简化逻辑,保证循环体至少执行一次。
- 缺点:通常用得较少,适用场景有限。
8. 使用Enumeration
(适用于旧版本集合)
Enumeration
是早期Java中的探索方式,主要用于旧版本集合(如Vector
)。
Enumeration<SmbmsUser> e = Collections.enumeration(list);
while (e.hasMoreElements()) {
SmbmsUser user = e.nextElement();
System.out.println(user);
}
- 优点:与早期的 Java 集合兼容。
- 简介: 最初于
Iterator
,功能较弱,现在不常用。