1. Iterator——迭代器:
1) 和C++中迭代器的概念一样,二要素:
i. 迭代器必定从属于某个容器,其作用就是用来遍历所属容器中的元素的!
ii. 迭代器是在容器的数据视图之上进行迭代,因此不能再迭代过程中修改容器中的数据,否则会抛出异常!除非使用迭代器的专用方法对数据进行修改;
2) Java的迭代器只在Collection中有,而Map没有迭代器,它有不同的迭代方法;
3) 迭代器的终极目标:就是用统一的方法来迭代不同类型的集合!可能由于不同集合的内部数据结构不尽相同,如果要自己纯手工迭代的话相互之间会有很大的差别,而迭代器的作用就是统一的方法对不同的集合进行迭代,而在迭代器底层隐藏不同集合之间的差异,从而为迭代提供最大的方便;
4) 用迭代器迭代的步骤:
i. 第一步肯定是先获取集合的迭代器:调用集合的iterator方法就能获得,Iterator
ii. 使用迭代器的hasNext、next往下迭代,而hasNext和next在很多地方都见到过,非常熟悉!这就是Java的方便之处;
2. Iterator的常用方法:
1) boolean hasNext(); // 是否还有下一个元素(肯定有一个位置指针维护者当前迭代的位置)
2) Object next(); // 取出下一个元素并返回
3) void remove(); // 从容器中删除当前元素(即上一个next代表的那个元素),直接会改变容器中的数据!
!!由于Java容器都是泛型类模板,因此容器可以记忆元素的具体类型,因此可以放心使用,只不过取出元素后要进行类型转换后才能正常使用!
!!!使用迭代器next获得的元素是一个集合中对应元素的深拷贝(即数据视图),如果对迭代变量进行修改是不会修改集合中的原数据的!!
!!同样,也不能直接在迭代过程中使用c.remove等方法对集合进行修改,因为迭代器已经锁定住集合了,强行修改会抛出异常!只能用Iterator的专用修改集合元素的方法修改才是正确的,就像上面的Iterator.remove方法;
4) 模板:
public class Test {
public static void main(String[] args) {
Collection c = new ArrayList(); // ArrayList是Collection的一个实现类,默认元素类型为Object
Iterator it = c.iterator();
while (it.hasNext()) {
Type var = it.next(); // 迭代值(数据视图)
对var进行操作;
c.remove(); // 错误!!在迭代过程中使用非迭代器方法对集合进行修改会直接抛出异常!!
}
}
}
!!可以看到,实际上,Iterator迭代的“集合”是真正集合的视图,视图和真实数据之间是一一映射的关系,如果此时使用非迭代器方法对真实数据进行修改就会导致真实数据和映像之间不一致,因此会抛出异常,而迭代器的修改方法可以保证这种映射的一致性,即迭代器先对视图进行修改,然后将视图的修改更新到真实数据,但是反向就是无效的,因为映像自己是知道关联的是哪个真实数据,但是真实数据本身不知道有哪些映像和我关联的,即真实数据永远是被动的,而映像是主动的!
3. Lambda表达式结合迭代器进行遍历——forEachRemaining方法:
1) Iterator专门提供了一个forEachRemaining方法可以专门使用Lambda表达式进行遍历,以完成一些强大的功能(同时保证代码的高度简洁);
2) 原型:default void Iterator.forEachRemaining(Consumer super E> action); // 里面又是一个函数闭包Consumer action,用来定义对当前迭代变量进行何种操作
3) 里面的action同样是接受每次迭代的变量,相当于上面代码"Type var = it.next()“中的var,同样也是数据视图,不要在action中用尝试修改集合中的元素
4) 示例:it.forEachRemaining(ele -> System.out.println(ele)); // 打印每个元素
4. Java 8新增的Predicate集合过滤方法:
1) Predicate是一种谓词动作接口:是一个函数式接口,即表示一个动作
public interface Predicate {
boolean test(T t);
}
!!即在test中给出一种关于变量t的测试条件;
2) 该接口主要用来筛选满足该判断条件的集合元素;
3) Java 8为Collection新增了一个支持根据Predicate条件判断来筛选集合元素的方法:
i. 该方法是:default boolean Collection.removeIf(Predicate super E> filter); // 可以批量删除满足Predicate filter条件的所有元素
ii. 示例:c.removeIf(ele -> ele.length() < 10); // 批量删除所有长度小于10的元素
iii. 目前只增加了一个removeIf,未来可能会增加更多Predicate筛选方法;
5. 灵活运用Predicate:
1) 毕竟Predicate就是一个函数式接口,你就可以把它当做C语言函数指针使用;
2) 示例:
public class Test {
public static void operate(Collection c, Predicate p) { // 满足谓词条件p的元素都打印出来
for (Object ele: c) {
if (p.test(ele)) {
System.out.println(ele);
}
}
}
public static void main(String[] args) {
Collection c = new ArrayList();
for (int i = 0; i < 10; i++) { // 加入0 ~ 9的字符串
c.add(String.valueOf(i));
}
operate(c, ele -> Integer.valueOf((String)ele) > 3); // 大于3的打印出来
}
}