五、集合——2-Collection接口和Iterator接口
2-Collection接口和Iterator接口
1.概述
(1)Collection接口是Set、Queue和List接口的父接口;
(2)Collection中定义了如下常用方法操作Collection集合中的元素
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; //Collection为List、Set、Queue接口的父接口 //即在Collection中定义的方法适用于List、Set、Queue //以List为例 public class CollectionTest { public static void main(String[] args) { /* * Collection接口中的常用方法 */ //创建List集合 Collection listA = new ArrayList(); Collection listB = new ArrayList(); //添加元素
//所有的Collection接口的实现类都重写了toString()方法 listA.add("AA"); listA.add("AB"); listA.add("AC"); listB.add("BA"); listB.add("BB"); listB.add("BC"); System.out.println(listA); System.out.println(listB); //把集合listB中的元素全部添加(复制)到listA中 listA.addAll(listB); System.out.println(listA); System.out.println(listB); //清除集合中的所有元素 Collection listC = new ArrayList(); listC.add("CA"); listC.add("CB"); listC.add("CC"); System.out.println(listC); listC.clear(); System.out.println(listC); //返回集合中是否包含指定元素 System.out.println("listA集合中是否包含字符串AA:"+listA.contains("AA")); //listA集合中是否包含listB集合 System.out.println("listA集合是否包含listB集合:"+listA.containsAll(listB)); //判断集合是否为空,即集合长度为0 System.out.println("listC集合长度是否为0:"+listC.isEmpty()); //获取Iterator对象(此对象用于遍历集合) Iterator iterator = listA.iterator(); //删除集合中的指定元素 listA.remove("AA"); System.out.println(listA); //从listA中删除listB所包含的所有元素 listA.removeAll(listB); System.out.println(listA); listA.addAll(listB); //把listA变为listA和listB的交集 listA.retainAll(listB); System.out.println(listA); //获取集合元素个数 System.out.println("listA中的元素个数为:"+listA.size()); //把集合转变为与其元素对应的数组 Object[] objs = listA.toArray(); System.out.println(objs); for(Object obj:objs){ System.out.println(obj); } } }
2.使用Lambda表达式遍历集合
(1)Iterable接口是Collection接口的父接口,在Iterable接口中提供了forEach(Consumer action)方法,可以使用该方法遍历Collection集合的元素,Consumer接口是一个函数式接口,所以可以使用Lambda表达式遍历集合。(函数式接口:接口中的方法唯一);
(2)Consumer接口中唯一的方法为accept(T t);
(3)使用Lambda表达式遍历Collection集合:
import java.util.ArrayList; import java.util.Collection; import java.util.function.Consumer; //Iterable是Collection接口的父接口 //在Iterable接口中定义了forEach(Consumer action)方法用来遍历集合 //Consumer接口是一个函数式接口,所以可以使用Lambda表达式遍历集合元素 public class ForEachTest { public static void main(String[] args) { //创建Collection集合 Collection list = new ArrayList(); //添加元素 list.add("a"); list.add("b"); list.add("c"); //调用forEach()方法,使用Lambda表达式遍历集合元素 list.forEach(obj->System.out.println(obj)); //使用实现接口的方式使用forEach()方法 list.forEach(new Consumer(){ @Override public void accept(Object obj) { // TODO Auto-generated method stub System.out.println(obj); }}); } }
3.使用Iterator遍历集合元素
(1)Iterator用于遍历Collection集合元素,Iterator对象也被成为迭代器;
(2)Iterator接口中定义的四个方法:
①boolean hasNext():被迭代的集合未被遍历完,返回true;
②Object next():返回集合里的下一个元素;
③void remove():删除集合里上一次next方法返回的元素;
④void forEachRemaining(Consumer action):可以通过该方法使用Lambda表达式遍历集合元素;
(3)Iterator的使用:
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class IteratorTest { public static void main(String[] args) { //Iterator用于遍历Collection集合 //创建Collection集合 Collection list = new ArrayList(); list.add("a"); list.add("b"); list.add("c"); //创建Iterator对象 Iterator iterator = list.iterator(); //遍历集合 while(iterator.hasNext()){ String str = (String)iterator.next(); if(str.equals("a")){ //从集合中删除上一次next()的元素 iterator.remove(); } //注意:在Iterator中对变量赋值,不会修改集合中的元素 str = "d"; } System.out.println(list); } }
(4)注意:
①在Iterator中迭代的元素并不是集合元素的本身,所以在对迭代变量修改时并不能修改集合中对应的元素,只有通过Iterator的remove()方法才能删除上次next()方法返回的集合元素,并对集合产生影响;
②除了使用Iterator的remove()方法外,不要在迭代过程中对集合进行修改,否则会出现异常。
4.使用Lambda表达式遍历Iterator
(1)类似于Iterable接口中的forEach(Consumer action)方法,也可通过Iterator的forEachRemaining(Consumer action)方法使用Lambda表达式遍历Iterator。
(2)注意,其遍历的是Iterator不是集合本身:
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class ForEachRemainingTest { public static void main(String[] args) { Collection list = new ArrayList(); list.add("a"); list.add("b"); list.add("c"); Iterator iterator = list.iterator(); //使用Iterator的forEachRemaining()方法,遍历Iterator iterator.forEachRemaining(obj->System.out.println(obj)); } }
5.foreach遍历集合元素
(1)类似于使用foreach遍历数组,需要注意的是,使用foreach遍历时,foreach的迭代变量也并非集合元素本身,修改迭代变量的值对集合没有影响,同样,类似于Iterator,不可以在循环中修改集合,否则会出现异常。
(2)foreach遍历集合元素的使用:
import java.util.ArrayList; import java.util.Collection; public class MyForeachTest { public static void main(String[] args) { Collection list = new ArrayList(); list.add("a"); list.add("b"); list.add("c"); for(Object obj:list){ System.out.println(obj); } } }
6.Predicate
(1)使用Predicate过滤集合:
在Collection接口中有一个removeIf(Predicate filter)方法,该方法会批量删除符合filter的所有元素。该方法的参数Predicate接口是一个函数式接口(方法test()唯一),所以也可以使用Lambda表达式使用此方法;
import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.function.Predicate; //使用Collection的removeIf(Predicate filter)方法过滤集合 public class PredicateTestA { public static void main(String[] args) { Collection list = new ArrayList(); list.add("aab"); list.add("aac"); list.add("abc"); list.add("bcd"); //使用removeIf(Predicate filter)方法删除带有aa字符串的字符串 list.removeIf(ele->((String)ele).contains("aa")); System.out.println(list); Collection set = new HashSet(); set.add("aab"); set.add("aac"); set.add("abc"); set.add("cbd"); //不使用Lambda表达式,直接使用实现Predicate接口的方式,过滤元素 set.removeIf(new Predicate(){ @Override public boolean test(Object t) { // TODO Auto-generated method stub if(((String)t).contains("aa")){ return true; //返回值为true的将被过滤掉 }else{ return false; } }}); System.out.println(set); } }
(2)使用Predicate简化集合的运算:
使用Predicate可以简化一些对集合较为复杂的运算需求:
实现以下需求,有Student对象若干,其属性sex为“女”的统计数量;属性sex为男的统计数量;统计属性score>60的数量,代码如下:
Student类:
public class Student { private String name; private String sex; private int score; public Student(){ } public Student(String name,String sex,int score){ this.name = name; this.sex = sex; this.score = score; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } }
PredicateUtil类:
import java.util.Collection; import java.util.function.Predicate; public class PredicateUtil { public static int count(Collection stus,Predicate p){ int count = 0; for(Object stu:stus){ if(p.test(stu)){ count++; } } return count; } }
Test类:
import java.util.ArrayList; import java.util.Collection; public class Test { public static void main(String[] args) { Student stuA = new Student("A","男",65); Student stuB = new Student("B","女",70); Student stuC = new Student("C","男",80); Student stuD = new Student("D","男",51); Student stuE = new Student("E","女",50); Student stuF = new Student("F","女",65); Student stuG = new Student("G","男",66); //创建集合存放Student对象 Collection stus = new ArrayList(); stus.add(stuA); stus.add(stuB); stus.add(stuC); stus.add(stuD); stus.add(stuE); stus.add(stuF); stus.add(stuG); //统计 //sex属性为男的数量 int nan = PredicateUtil.count(stus, stu->((Student)stu).getSex().equals("男")); //sex属性为女的数量 int nv = PredicateUtil.count(stus, stu->((Student)stu).getSex().equals("男"));; //score>60的数量 int score = PredicateUtil.count(stus, stu->((Student)stu).getScore()>60); //输出 System.out.println(nan); System.out.println(nv); System.out.println(score); } }
7.Stream
(1)Stream、IntStream、LongStream、DoubleStream等流式API代表多个支持串行和并行聚集操作的元素。在这几个接口中,Stream是一个通用的流接口,其余的分别代表元素类型为int、long和double;
(2)独立使用Stream的步骤如下:
①使用Stream的builder()类方法创建该Stream对应的Builder;
②重复调用Builder的add()方法向该流中添加多个元素;
③调用Builder的buil()方法获取对应的Stream;
④调用Stream的聚集方法;
对于大多数的聚集方法,这些方法只能执行一次;
(3)Stream中的聚集方法
1)中间方法:允许流保持打开状态,并允许直接调用后续方法;
2)末端方法:对流的最终操作,当执行过末端方法后,该流将变为不可用的状态并被消耗;
这些聚集方法,都是用于对Stream中的元素进行操作,或者操作Stream集合。
(4)Collection接口提供了一个stream()方法,该方法可以返回此集合对应的流,在获得对应的流之后就可以通过流式API操作集合元素。使用Stream直接对集合中所有元素进行批量操作:
import java.util.ArrayList; import java.util.Collection; public class Test2 { public static void main(String[] args) { //创建由Student构成的集合 Student stuA = new Student("A","男",65); Student stuB = new Student("B","女",70); Student stuC = new Student("C","男",80); Student stuD = new Student("D","男",51); Student stuE = new Student("E","女",50); Student stuF = new Student("F","女",65); Student stuG = new Student("G","男",66); //创建集合存放Student对象 Collection stus = new ArrayList(); stus.add(stuA); stus.add(stuB); stus.add(stuC); stus.add(stuD); stus.add(stuE); stus.add(stuF); stus.add(stuG); //统计sex为男的数量 int nan = (int) stus.stream().filter(stu->((Student)stu).getSex().equals("男")).count(); System.out.println(nan); //统计sex为女的数量 int nv = (int) stus.stream().filter(stu->((Student)stu).getSex().equals("女")).count(); System.out.println(nv); //统计score>60的数量 int score = (int) stus.stream().filter(stu->((Student)stu).getScore()>60).count();; System.out.println(score); } }