1. Java集合框架:
1) Java中集合就是用来存放多个元素的数据结构,可能你会想到数组也可以存放多个元素,但是数组可以保存基本类型,而Java的集合只能保存引用类型数据!!
2) Java将集合分成两大类,一类是具有关联关系的集合(即映射关系,以Map为代表的根接口),另一类是无关联关系的集合(像链表、集合之类的,以Collection为代表的根接口),也就是说Collection和Map是所有Java集合的根接口,从它们两个派生出了很多具体的集合实现类;
!!Java集合也是要求元素类型一致的,只不过它使用泛型模板来规定类型的一致,如果类型使用Object,那么所有类型都是其子类,那就可以存放任意类型了!!
3) Collection的直接子接口:无关联集合,其下直接派生出了三种接口,Set、List、Queue
i. Set:无序、不可重复集合;
ii. List:有序、可重复集合;
iii. Queue:队列,特殊的无关联集合(FIFO);
4) Map的直接子接口:关联集合,保存键值对,其下派生出了很多实现类,其中最常用的几种有
i. HashMap:线程不安全,键值允许为null
ii. HashTable:线程安全,键值不能为null
iii. SortedMap:有序Map
iv. EnumMap:枚举Map
!!Java集合都重载了toString方法,因此可以直接打印出其中的元素!
2. Collection接口:
1) 是所有无关联集合的根接口,其中的方法在所有派生类中都存在(也就是在Set、List、Queue以及其实现类中都可以使用);
2) 接下来介绍的都是Collection的对象方法;
3) 添加元素:成功添加返回true
i. boolean add(Object o); // 添加一个元素
ii. boolean addAll(Collection c); // 将c中的所有元素加入
4) 删除元素:成功删除返回true
i. boolean remove(Object o); // 删除指定元素,只删除第一个找到的
ii. boolean removeAll(Collection c); // 删除c中所有的元素,相当于集合相减
iii. boolean retainAll(Collection c); // 删除c中不包含的元素,相当于集合相交
iv. void clear(); // 清空集合
5) 检查是否包含某个元素:
i. boolean contains(Object o); // 是否包含指定元元素o
ii. boolean contains(Collection c); // 是否包含集合c中的所有元素
6) 功能方法:
i. 查看集合中元素的个数:int size();
ii. 判空:boolean isEmpty();
iii. 把集合转换成一个数组:Object[] toArray();
7) 示例:
public class Test {
public static void main(String[] args) {
Collection c = new ArrayList(); // ArrayList是Collection的一个实现类,默认元素类型为Object
c.add("mama");
c.add(5); // 虽然不能装基本类型,但是Java支持自动包装,将基本类型包装秤包装器类型
System.out.println(c.size()); // 2
c.remove(5);
System.out.println(c.size()); // 1
System.out.println(c.contains("mama")); // true
c.add("fafa");
System.out.println(c); // [mama, fafa]
Collection d = new HashSet(); // HashSet也是Collection的一个实现类
d.add("fafa");
d.add("coco");
System.out.println(c.containsAll(d)); // false
c.removeAll(d); // c - d
System.out.println(c); // [mama]
c.clear();
System.out.println(c); // []
d.retainAll(c);
System.out.println(d); // []
}
}
!!这里我们先忽略泛型,因此编译警告先忽略;
3. forEach/Consumer:
1) 从Java 8开始,Java为很多“集合类型”(不仅仅指Collection和Map,还有其它很多保存多个元素的结构类型)的类提供了forEach方法为遍历元素提供方便;
2) 其原型为:default void 集合类型对象.forEach(Consumer<? super T> action); // 这里的Consumer<? super T>类型就简单的理解为Consumer接口即可
3) 可以看到这类方法用default关键字修饰,也就是说是一种默认的功能方法;
4) 使用forEach的遍历原理:集合会在遍历时将每个元素在每轮遍历时交给action进行处理,而具体怎么处理(比如打印该元素,或者进行一些其他操作)由action自己定义,即action就是操作元素的动作;
5) 再来看一下Consumer接口:
public interface Consumer<T> {
void accept(T t);
}
!它是一个典型的函数式接口,而其中的参数t就是每次遍历时传进来的元素,accept表示接受该元素,而该方法体中就是操作元素的定义了;
!!也就是说forEach的参数其实就是一个函数指针,该函数定义了该如何操作每次遍历得到的集合元素,典型的函数闭包;
!!由于Consumer是函数式接口,因此可以非常方便地使用Lambda表达式来遍历;
6) 示例——打印每个元素:Collection c = ...; c.forEach(ele -> System.out.println(ele));
4. 传统的forEach遍历集合:
1) 当然,Java集合也支持普通的forEach遍历,就像forEach遍历数组一样;
2) 使用方法:
for (type ele: collection) {
...
}
3) Java的forEach使用的注意事项:
i. forEach底层是一个数据视图,即从集合中提取数据的视图,然后你遍历的其实是视图;
ii. 我们都知道视图的特性是只读的,因此如果你强行要在forEach体中修改集合中的元素将会抛出异常!!
iii. 其中的接受变量ele只是一个临时变量,不要企图在forEach体中对其进行修改,不会产生任何效果,而如果你强行采用特殊方式修改集合中的元素将会像上述所说的那样抛出异常的!!比如:在forEach体中写coolection.remove(...); 之类的可以直接修改集合元素的语句(并不能用ele修改集合元素);