集合
集合类是用来存放某类对象
的。集合类有一个共同特点,就是它们只容纳对象
(实际上是对象名,即指向地址的指针
)。这一点和数组不同,数组可以容纳对象和简单数据
。如果在集合类中既想使用简单数据类型,又想利用集合类的灵活性,就可以把简单数据类型数据变成该数据类型类的对象,然后放入集合中处理,
但这样执行效率会降低。比如说基本数据类型的封装类,int类型对应的封装类为Integer, long类型对应的封装类为Long类型
集合类容纳的对象都是Object类
的实例(所有对象继承于Object类
),一旦把一个对象置入集合类中,它的类信息将丢失,也就是说,集合类中容纳的都是指向Object类对象的指针
。这样的设计是为了使集合类具有通用性,因为Object类是所有类的祖先
,所以可以在这些集合中存放任何类而不受限制。当然这也带来了不便,这令使用集合成员之前必须对它重新造型。
Collection接口
Collection是一个基本的集合接口
,Collection中可以容纳一组集合元素
(Element),Collection有两个重要的子接口List和Set
。List表达一个有序的集合
,List中的每个元素都有索引
,使用此接口能够准确的控制每个元素插入的位置。用户也能够使用索引来访问List中的元素,List类似于Java的数组
。Set接口的特点是不能包含重复的元素
。对Set中任意的两个元素element1和element2都有element1.equals(element2)==false。另外,Set最多有一个null元素。
Collection继承树
Collection的Api文档
boolean add(E e) 该方法用于向集合里添加一个元素。如果集合对象被添加操作改变了,则返回 true 。
boolean addAll(Collection<? extends E> c)该方法把集合 c 里的所有元素添加到指定集合里。 如果集合对象被添加操作改变了 , 则返回 true 。
void clear() 清除集合里的所有元素,将集合长度变为 0 。
boolean contains(Object o) 返回集合里是否包含指定元素 。
boolean containsAll(Collection<?> c) 返回集合里是否包含集合 c 里的所有元素。
boolean equals(Object o) 将指定的对象与此集合进行比较,以进行相等性
int hashCode() 返回此集合的哈希代码值。
boolean isEmpty() 返回集合是否为空。当集合长度为 0 时返回 true ,否则返回 false 。
Iterator<E> iterator() 返回此集合中的元素的迭代器。
default Stream<E> parallelStream() 返回一个可能并行 Stream与集合的来源。
boolean remove(Object o) 删除集合中的指定元素。当集合中包含了一个或多个元素时,该方法只删除第一个符合条件的元素 ,该方法将返回true。
boolean removeAll(Collection<?> c) 从集合中删除集合 c 里包含的所有元素( 相当于用调用该方法
的集合减集合 c) ,如果删除了一个或一个以上的元素,则该方法返回 true 。
default boolean removeIf(Predicate<? super E> filter) 删除满足给定谓词的这个集合的所有元素。
boolean retainAll(Collection<?> c) 从集合中删除集合 c 里包含的所有元素( 相当于用调用该方法的集合减集合 c) ,如果删除了一个或一个以上的元素,则该方法返回 true 。
int size() 返回此集合中的元素的数目。
default Spliterator<E> spliterator() 创建此集合中的元素的 Spliterator。
default Stream<E> stream() 返回一个序列 Stream与集合的来源。
Object[] toArray() 返回包含此集合中所有元素的数组。
< T > T[] toArray(T[] a) 返回包含此集合中所有元素的数组;返回数组的运行时类型是指定的数组的运行时类型。
实例代码
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
/**
* @Author: 随风飘的云
* @Description:
* @Date: 2022/3/18 0:26
* @Modified By:
*/
public class CollectionTest
{
public static void main(String[] args){
Collection c = new ArrayList();
// 添加元素
c.add("孙悟空");
// 虽然集合里不能放基本类型的值,但Java支持自动装箱
c.add(6);
System.out.println("c集合的元素个数为:" + c.size()); // 输出2
// 删除指定元素
c.remove(6);
System.out.println("c集合的元素个数为:" + c.size()); // 输出1
// 判断是否包含指定字符串
System.out.println("c集合的是否包含\"孙悟空\"字符串:"
+ c.contains("孙悟空")); // 输出true
c.add("轻量级Java EE企业应用实战");
System.out.println("c集合的元素:" + c);
Collection books = new HashSet();
books.add("轻量级Java EE企业应用实战");
books.add("疯狂Java讲义");
System.out.println("c集合是否完全包含books集合?"
+ c.containsAll(books)); // 输出false
// 用c集合减去books集合里的元素
c.removeAll(books);
System.out.println("c集合的元素:" + c);
// 删除c集合里所有元素
c.clear();
System.out.println("c集合的元素:" + c);
// 控制books集合里只剩下c集合里也包含的元素
books.retainAll(c);
System.out.println("books集合的元素:" + books);
}
}
结果
Map接口
Map没有继承Collection接口,与Collection是并列关系。Map提供键(key)到值(value)的映射。一个Map中不能包含相同的键,每个键只能映射一个值。
Map集合继承树
Map的Api接口
void clear() 从这个映射中移除所有的映射(可选操作)。
default V compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction) 试图计算出指定键和当前的映射值的映射(或 null如果没有当前映射)。
default V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction) 如果指定的键是不是已经与价值相关的(或映射到 null),尝试使用给定的映射功能,进入到这个Map除非 null计算其价值。
default V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V>remappingFunction) 如果指定键的值是存在和非空的,尝试计算一个新的映射,给出了键和它当前的映射值。
boolean containsKey(Object key) 返回 true如果这Map包含一个指定的键映射。
boolean containsValue(Object value) 返回 true如果映射到指定的值的一个或多个键。
Set<Map.Entry<K,V>> entrySet() 返回一个 Set视图的映射包含在这个Map。
boolean equals(Object o) 将指定的对象与此映射的相等性进行比较。
default void forEach(BiConsumer<? super K,? super V> action) 在该映射中的每个条目执行给定的操作,直到所有的条目被处理或操作抛出异常。
V get(Object key) 返回指定的键映射的值,或 null如果这个Map不包含的键映射。
default V getOrDefault(Object key, V defaultValue) 返回指定的键映射的值,或 defaultValue如果这个Map不包含的键映射。
int hashCode() 返回此映射的哈希代码值。
boolean isEmpty() 返回 true如果这个Map不包含键值的映射。
Set<K> keySet() 返回一个 Set的关键视图包含在这个Map。
default V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction) 如果指定的键已与值相关联的值或与空值相关联的,则将其与给定的非空值关联。
V put(K key, V value) 将指定的值与此映射中的指定键关联(可选操作)。
void putAll(Map<? extends K,? extends V> m) 从指定的映射到这个Map(可选操作)复制所有的映射。
default V putIfAbsent(K key, V value) 如果指定的键是不是已经与价值相关的(或映射到 null)将其与给定的值并返回 null,否则返回当前值。
V remove(Object key) 如果存在(可选操作),则从该Map中移除一个键的映射。
default boolean remove(Object key, Object value) 仅当它当前映射到指定的值时,为指定的键移除条目。
default V replace(K key, V value) 仅当它当前映射到某一值时,替换指定的键的条目。
default boolean replace(K key, V oldValue, V newValue) 仅当当前映射到指定的值时,替换指定的键的条目。
default void replaceAll(BiFunction<? super K,? super V,? extends V> function) 将每个条目的值替换为在该项上调用给定函数的结果,直到所有的条目都被处理或函数抛出异常。
int size() 返回这个映射中的键值映射的数目。
Collection<V> values() 返回一个 Collection视图的值包含在这个Map。
集合的遍历
使用Lambda表达式遍历
Java 8 为Iterable 接口新增了 一个 forEach(Consumer action)默认方法
, 该方法所需参数的类型是一个函数式接口
,而Iterable 接口是 Collection 接口的父接口
,因此 Collection 集合也可直接调用该方法。当程序调用 Iterable 的 forEach(Consumer action)遍历集合元素 时, 程序会依次将集合元素传给
Consumer 的 accept(T t)方法(该接口中唯一 的抽 象方法)。正因Consumer 是函数式接口,因此可以使用 Lambda 表达式来遍历集合元素。
实例代码
import java.util.Collection;
import java.util.HashSet;
public class CollectionEach{
public static void main(String[] args){
// 创建一个集合
Collection books = new HashSet();
books.add("轻量级Java EE企业应用实战");
books.add("疯狂Java讲义");
books.add("疯狂Android讲义");
// 调用forEach()方法遍历集合
books.forEach(obj -> System.out.println("迭代集合元素:" + obj));
}
}
结果:
使用java8增强的Iterator遍历集合元素
Iterator 接口也是 Java 集合框架的成员,Iterator 则主要用于遍历( 即迭代访 问 ) Collection集合中的元素, Iterator 对象也被称为迭代器。
Iterator的API文档
boolean hasNext(): 如果被迭代的集合元素还没有被遍历完 ,则返回 true 。
Object next(): 返回集合里的 下一个元素。
void remove(): 删除集合里上一次next方法返回的元素。
void forEachRemaining(Consumer action) ,这是 Java 8 为Iterator新增的默认方法, 该方法可使用Lambda 表达式来遍历集合元素。
实例代码
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class IteratorTest {
public static void main(String[] args) {
// 创建集合、添加元素的代码与前一个程序相同
Collection books = new HashSet();
books.add("轻量级Java EE企业应用实战");
books.add("疯狂Java讲义");
books.add("疯狂Android讲义");
// 获取books集合对应的迭代器
Iterator it = books.iterator();
while(it.hasNext())
{
// it.next()方法返回的数据类型是Object类型,因此需要强制类型转换
String book = (String)it.next();
System.out.println(book);
if (book.equals("疯狂Java讲义"))
{
// 从集合中删除上一次next方法返回的元素
it.remove();
}
// 对book变量赋值,不会改变集合元素本身
book = "测试字符串"; //①
}
System.out.println(books);
}
}
结果:
当使用 Iterator 迭代访问 Collection 集合元素
时, Collection 集合里 的元素不能被改变
,只有通过Iterator 的 remove()方法删 除 上 一 次 next()方法返回 的集合元素才可以
;否则将会发生异常。
实例代码
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class IteratorErrorTest {
public static void main(String[] args)
{
// 创建集合、添加元素的代码与前一个程序相同
Collection books = new HashSet();
books.add("a");
books.add("c");
books.add("b");
System.out.println(books);
System.out.println();
// 获取books集合对应的迭代器
Iterator it = books.iterator();
while(it.hasNext())
{
String book = (String)it.next();
if (book.equals("a"))
{
// 使用Iterator迭代过程中,不可修改集合元素,下面代码引发异常
books.remove(book);
System.out.println(book.hashCode());
}
}
}
}
结果
使用Lambda表达式遍历Iterator
实例代码
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class IteratorEach {
public static void main(String[] args) {
// 创建集合、添加元素的代码与前一个程序相同
Collection books = new HashSet();
books.add("我");
books.add("你");
books.add("他");
// 获取books集合对应的迭代器
Iterator it = books.iterator();
// 使用Lambda表达式(目标类型是Comsumer)来遍历集合元素
it.forEachRemaining(obj -> System.out.println("迭代集合元素:" + obj));
}
}
结果
Stream操作集合
java8新增了Stream, IntStream, LongStream, DoubleStream等流式Api,其中Stream是通用的流式APi,而其他的分别代表为int,long,double的流。
Stream的方法分类
1、中间方法: 中间操作允许流保持打开状态,并允许直接调用后续方法 。
2、末端方法: 末端方法是对流的最终操作 。 当对某个 Stream 执行末端方法后,该流将被"消耗"且不再可用
Stream的方法特征
1、状态的方法: 这种方法会给流增加一些新的属性,比如元素的唯一性、元素的最大数量、保证元素以排序的方式被处理等 。 有状态的方法往往需要更大的性能开销 。
2、短路方法 : 短路方法可以尽早结束对流的操作,不必检查所有的元素 。
Stream的Api方法
Stram的中间APi方法
filter(Predicate predicate): 过滤 Stream 中所有不符合 predicate 的元素 。
mapToXxx(ToXxxFunction m叩per): 使用 ToXxxFunction 对流中的元素执行一对一 的转换,该方
法返回的新流中包含了 ToXxxFunction 转换生成的所有元素 。
peek(Consumer action): 依次对每个元素执行一些操作,该方法返回的流与原有流包含相同的元素 。 该方法主要用于调试。
distinct(): 该方法用于排序流中所有重复的元素(判断元素重复的标准是使用 equals() 比较返回true) 。 这是一个有状态的方法 。
sorted(): 该方法用于保证流中的元素在后续的访问中处于有序状态 。 这是一个有状态的方法 。
limit(long maxSize): 该方法用于保证对该流的后续访
Stream的末端API方法
forEach(Consumer action): 遍历流中所有元素,对每个元素执行 action 。
toArray(): 将流中所有元素转换为一个数组 。
reduce(): 该方法有三个重载的版本,都用于通过某种操作来合并流中的元素 。
min(): 返回流中所有元素的最小值 。
max(): 返回流中所有元素的最大值 。
count(): 返回流中所有元素的数量。
anyMatch(Predicate predicate): 判断流中是否至少包含一个元素符合 Predicate 条件
allMatch(Predicate predicate): 判断流中是否每个元素都符合 Predicate 条件。
noneMatch(predicate predicate): 判断流中是否所有元素都不符合 Predicate 条件。
findFirst(): 返回流中的第一个元素。
findAny(): 返回流中的任意 一个元素。
实例代码
import java.util.Collection;
import java.util.HashSet;
/**
* @author: 随风飘的云
* @date 2022/03/18 22:20
*/
public class CollectionStream {
public static void main(String[] args) {
Collection collection = new HashSet();
collection.add("小红是一个三年级的学生");
collection.add("小红的爸爸是一个教师");
collection.add("语文,数学,英语是小红必须学的科目");
collection.add("小红是个男孩");
System.out.print("测试1:");
System.out.println(
// 设置Stream流
collection.stream()
// 过滤
.filter(count
// 判断Collection中包含有几个小红(4个)
-> ((String) count).contains("小红")).count());
// 输出1(判断语句中包含有语文的句子有多少个)
System.out.print("测试2:");
System.out.println(collection.stream().filter(
count -> ((String) count).contains("语文")).count());
// 输出2(判断语句长度大于10的有多少个)
System.out.print("测试3:");
System.out.println(collection.stream().filter(
str -> ((String) str).length() > 10).count());
//先调用Collection对象的stream()方法将集合转换为Stream
//再调用 Stream的 mapToInt ()方法获取原有的 Stream 对应的 IntStream
// 输出每一个句子的长度
System.out.println();
collection.stream().forEach(System.out::println);
collection.stream().mapToInt(len -> ((String) len).length()).forEach(System.out::println);
}
}
结果:
集合类的好处
使用Java提供的集合类有如下功能:
(1)降低编程难度:在编程中会经常需要链表、向量等集合类,如果自己动手写代码实现这些类,需要花费较多的时间和精力。调用Java中提供的这些接口和类,可以很容易的处理数据。
(2)提升程序的运行速度和质量:Java提供的集合类具有较高的质量,运行时速度也较快。使用这些集合类提供的数据结构,程序员可以从“重复造轮子”中解脱出来,将精力专注于提升程序的质量和性能。
(3)无需再学习新的APl:借助泛型,只要了解了这些类的使用方法,就可以将它们应用到很多数据类型中。如果知道了LinkedList的使用方法,也会知道LinkedList怎么用,则无需为每一种数据类型学习不同的API。
(4)增加代码重用性:也是借助泛型,就算对集合类中的元素类型进行了修改,集合类相关的代码也几乎不用修改。