资讯专栏INFORMATION COLUMN

Java 集合 Collection、Iterator

harryhappy / 1867人阅读

摘要:如果需要创建对象,则必须与一个被迭代的集合。这是一个有状态的方法该方法用于保证对该流的后续访问中最大允许访问的元素个数。可以对集合元素进行整体的聚集操作。

Java集合分为Set(无序、不可重复)、List(有序、重复)、Queue(队列)和Map(映射关系)

Java集合概述

数组元素既可以是基本类型的值,也可以是对象(实际保存对象的引用变量)
集合只能保存对象(实际保存对象的引用变量)

Collection和Map是Java集合框架的根接口

Collection集合体系的继承树

Map体系的继承树

所有的Map实现类用于保存具有映射关系的数据,Map保存的每项数据都是key-value对。
Map里的key是不可重复的,用于标识集合里的每项数据,如果需要查阅Map中的数据时,总是根据Map的key来获取

Collection和Iterator接口

Collection接口是List、Set和Queue接口的父接口,定义了如下操作集合元素的方法

boolean add(Object o):该方法用于向集合里添加一个元素。如果集合对象被添加操作改变了,则返回true

boolean addAll(Collection c):该方法把集合c里的所有元素添加到指定集合里。如果集合对象被添加操作改变了,则返回true

void clear():清除集合里的所有元素,将集合长度变为0

boolean contains(Object o):返回集合里是否包含指定元素

boolean containsAll(Collection c):返回集合里是否包含集合c里的所有元素

boolean isEmpty():返回集合是否为空,当集合长度为0时返回true,否则返回false

Iterator iterator():返回一个Iterator对象,用于遍历集合里的元素

boolean remove(Object o):删除集合中的指定元素o,当集合中包含了一个或多个元素o时,该方法只删除第一个符合条件的元素,该方法将返回true

boolean removeAll(Collection c):从集合中删除集合c里包含的所有元素(相当于调用该方法的集合减集合c),如果删除了一个或一个以上的元素,则返回true

boolean retainAll(Collection c):从集合中删除集合c里不包含的元素(相当于把调用该方法的集合和集合c的交集),如果该操作改变了调用该方法的集合,则该方法返回true

int size():该方法返回集合里元素的个数

Object[] toArray():该方法把集合转换成一个数组,所有的集合元素变成对应的数组元素

下面程序创建了两个Collection对象,一个是ArrayList的collection集合,另一个是HashSet的number集合。虽然实现类不同,但当成Collection来使用时,操作集合元素没有任何区别

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;

public class CollectionTest 
{
    public static void main(String[] args) 
    {
        Collection collection = new ArrayList<>(); 
        //添加元素
        collection.add("杜兰特");
        //虽然集合里不能放基本类型的值,但Java支持自动装箱
        collection.add(35);
        System.out.println("collection集合的元素个数为:" + collection.size());        //输出2
        //删除指定元素
        collection.remove(35);
        System.out.println("collection集合的元素个数为:" + collection.size());        //输出1    
        //判断是否包含指定字符串
        System.out.println("collection集合是否包含"杜兰特"字符串:"
                + collection.contains("杜兰特"));                                    //输出true
        collection.add("维斯布鲁克");
        System.out.println("collection集合的元素:" + collection);
        Collection number = new HashSet<>();
        number.add(35);
        number.add(0);
        System.out.println("collection集合是否完全包含number集合?" + collection.containsAll(number));        //输出false
        //用collection集合减去number集合里的元素
        collection.removeAll(number);
        System.out.println("collection集合的元素:" + collection);
        //删除collection集合里的所有元素
        collection.clear();
        System.out.println("collection集合的元素:" + collection);
        //控制number集合里只剩下collection集合里也包含的元素
        number.retainAll(collection);
        System.out.println("number集合的元素:" + number);
    }
}


collection集合的元素个数为:2    
collection集合的元素个数为:1
collection集合是否包含"杜兰特"字符串:true
collection集合的元素:[杜兰特, 维斯布鲁克]
collection集合是否完全包含number集合?false
collection集合的元素:[杜兰特, 维斯布鲁克]
collection集合的元素:[]
number集合的元素:[]
使用Lambda表达式遍历集合

Iterable接口的forEach(Consumer action)默认方法,该方法需要参数的类型是一个函数式接口,而Iterable接口是Collection接口的父接口,因此Collection集合可直接调用该方法

import java.util.Collection;
import java.util.HashSet;

public class CollectionEach 
{
    public static void main(String[] args)
    {
        //创建一个集合
        Collection teams = new HashSet<>();
        teams.add("Thunder");
        teams.add("Cavaliers");
        teams.add("Warriors");
        //调用forEach()方法遍历集合
        teams.forEach(obj -> System.out.println("迭代集合元素: " + obj));
    }
}

程序调用Iterable的forEach(Consumer action)遍历集合元素是,程序会依次将集合元素传给Consumer的accept(T t)方法(该接口中唯一的抽象方法)

使用Java8增强的Iterator遍历集合元素

Iterator主要用于遍历(即迭代访问)Collection集合中的元素,Iterator对象也被称为迭代器

boolean hasNext():如果被迭代的集合元素还没有被遍历完,则返回true

Object next():返回集合里的下一个元素

void remove():删除集合里上一次next方法返回的元素

void forEachRemaining(Consumer action):该方法可以使用Lambda表达式来遍历集合元素

Iterator仅用于遍历集合,Iterator本身并不提供盛装对象的能力。如果需要创建Iterator对象,则必须与一个被迭代的集合。当使用Iterator对集合元素进行迭代时,Iterator并不是把集合元素本身传给了迭代变量,而是把集合元素的值传给了迭代变量,所以修改迭代变量的值对集合元素本身没有任何影响

//获取teams集合对应的迭代器
Iterator iterator = teams.iterator();
while (iterator.hasNext())
{
    //iterator.next()方法返回的数据类型是Object类型,因此需要强制类型转换
    String team = (String) iterator.next();
    System.out.println(team);
    if (team.equals("Cavaliers")) 
    {
        //从集合中删除上一次next()方法返回的元素
        iterator.remove();
    }
    //对iterator变量赋值,不会改变集合元素本身
    team = "Rocket";        //①
}
System.out.println(teams);

当使用Iterator迭代访问Collection集合元素时,Collection集合里的元素不能被改变,只有通过Iterator的remove()方法删除上一次next()方法返回的集合元素才可以;否则将会引发java.util.ConcurrentModificationException异常

使用Lambda表达式遍历Iterator
//获取teams集合对应的迭代器
Iterator iterator = teams.iterator();
//使用Lambda表达式(目标类型是Comsumer)来遍历集合元素
iterator.forEachRemaining(obj -> System.out.println("迭代集合元素: " + obj));
使用foreach循环遍历集合元素

使用foreach循环来迭代访问Collection集合里的元素更加简洁,迭代变量不是集合元素本身,系统只是依次把集合元素的值赋给迭代变量,集合也不能被改变,否则引发ConcurrentModificationException异常

import java.util.*;

public class ForeachTest
{
    public static void main(String[] args)
    {
        // 创建集合、添加元素的代码与前一个程序相同
        Collection books = new HashSet();
        books.add(new String("轻量级Java EE企业应用实战"));
        books.add(new String("疯狂Java讲义"));
        books.add(new String("疯狂Android讲义"));
        for (Object obj : books)
        {
            // 此处的book变量也不是集合元素本身
            String book = (String)obj;
            System.out.println(book);
            if (book.equals("疯狂Android讲义"))
            {
                // 下面代码会引发ConcurrentModificationException异常
                books.remove(book);     //①
            }
        }
        System.out.println(books);
    }
}
使用Java8新增的Predicate操作集合

removif(Predicate filter)方法,该方法将会批量删除符合filter条件的所有元素。该方法需要一个Predicate(谓词)对象作为参数,Predicate也是函数式接口,因此可使用Lambda表达式作为参数

import java.util.*;
import java.util.function.*;

public class PredicateTest2
{
    public static void main(String[] args)
    {
        // 创建books集合、为books集合添加元素的代码与前一个程序相同。
        Collection books = new HashSet();
        books.add(new String("轻量级Java EE企业应用实战"));
        books.add(new String("疯狂Java讲义"));
        books.add(new String("疯狂iOS讲义"));
        books.add(new String("疯狂Ajax讲义"));
        books.add(new String("疯狂Android讲义"));
        // 统计书名包含“疯狂”子串的图书数量
        System.out.println(calAll(books , ele->((String)ele).contains("疯狂")));
        // 统计书名包含“Java”子串的图书数量
        System.out.println(calAll(books , ele->((String)ele).contains("Java")));
        // 统计书名字符串长度大于10的图书数量
        System.out.println(calAll(books , ele->((String)ele).length() > 10));
    }
    public static int calAll(Collection books , Predicate p)
    {
        int total = 0;
        for (Object obj : books)
        {
            // 使用Predicate的test()方法判断该对象是否满足Predicate指定的条件
            if (p.test(obj))
            {
                total ++;
            }
        }
        return total;
    }
}
使用Java8新增的Stream操作集合

独立使用Stream的步骤

使用Stream或XxxStream的builder()类方法创建该Stream对应的Builder

重复调用Builder的add()方法向该流中添加多个元素

调用Builder的build()方法获取对应的Stream

调用Stream的聚集方法

Stream提供了大量的聚集方法供用户调用,对于大部分聚集方法而言,每个Stream只能执行一次

import java.util.stream.IntStream;

import javax.lang.model.element.Element;
import javax.print.attribute.standard.PrinterLocation;
import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction;

public class IntStreamTest 
{
    public static void main(String[] args) 
    {
        IntStream is = IntStream.builder()
                .add(20)
                .add(16)
                .add(12)
                .add(22)
                .build();
        //下面调用聚集方法的代码每次只能执行一行
        System.out.println("is所有元素的最大值:" + is.max().getAsInt());
        System.out.println("is所有元素的最小值:" + is.min().getAsInt());
        System.out.println("is所有元素的总和:" + is.sum());
        System.out.println("is所有元素的总数:" + is.count());
        System.out.println("is所有元素的平均值:" + is.average());
        System.out.println("is所有元素的平方是否都大于20:" + is.allMatch(ele -> ele * ele > 20));
        System.out.println("is是否包含任何元素的平方大于20:" + is.anyMatch(ele -> ele * ele > 20));
        //将is映射成一个新Stream,新Stream的每个元素是原Stream元素的2倍+1
        IntStream newIs =  is.map(ele -> ele * 2 + 1);
        //使用方法引用的方式来遍历集合元素
        newIs.forEach(System.out::println);
    }
}

使用流的时候应当格外注意,它只能消费一次。上述聚集方法执行操作每次只能执行一行,否则出现java.lang.IllegalStateException: stream has already been operated upon or closed

Stream提供了大量的方法进行聚集操作,这些方法既可以是“中间的”(intermediate),也可以是“末端的”(terminal)

中间方法:中间操作允许流保持打开状态,并允许直接调用后续方法。map()方法就是中间方法。中间方法的返回值是另外一个流

末端方法:末端方法是对流的最终操作。当对某个Stream执行末端方法后,该流就会被“消耗”且不再可用。sum()、count()、average()等方法都是末端方法。

流方法的两个特征

有状态的方法:该方法会给流增加一些新的属性,比如元素的唯一性、元素的最大数量、保证元素以排序的方式被处理等。有状态的方法往往需要更大的性能开销

短路方法:可以尽早结束对流的操作,不必检查所有的元素

常用中间方法

filter(Predicate predicate):过滤Stream中所有不符合predicate的元素

mapToXxx(ToXxxFunction mapper):使用ToXxxFunction对流中的元素执行一对一的转换,该方法返回的新流中包含了ToXxxFunction转换生成的所有元素

peek(Consumer action):依次对每个元素执行一些操作,该方法返回的流与原有流包含相同的元素。主要用于调试

distinct():该方法用于排序流中所有重复的元素(判断元素重复的标准是使用equals()比较返回true)。这是一个有状态的方法

sorted():该方法用于保证流中的元素在后续的访问中处于有序状态。这是一个有状态的方法

limit(long maxSize):该方法用于保证对该流的后续访问中最大允许访问的元素个数。这是一个有状态的、短路方法

forEach(Consumer action):遍历流中所有元素,对每个元素执行action

toArray():将流中所有元素转换为一个数组

reduce():该方法有三个重载版本,都用于通过某种操作来合并流中的元素

min():返回流中所有元素的最小值

max():返回流中所有元素的最大值

count():返回流中所有元素的数量

anyMatch(Predicate predicate):判断流中是否至少包含一个元素符合Predicate条件

allMatch(Predicate predicate):判断流中是否每个元素都符合Predicate条件

noneMatch(Predicate predicate):判断流中是否所有元素都不符合Predicate条件

findFirst():返回流中的第一个元素

findAny():返回流中的任意一个元素

Java8允许使用流式API来操作集合,Collection接口提供了一个stream()默认方法可返回该集合对应的流,接下来即可通过流式API来操作集合元素。Stream可以对集合元素进行整体的聚集操作。

public class CollectionStream 
{
    public static void main(String[] args) 
    {
        Collection player = new HashSet<>();
        player.add(new String("FMVP+MVP勒布朗詹姆斯"));
        player.add(new String("MVP德里克罗斯"));
        player.add(new String("MVP斯蒂芬库里"));
        player.add(new String("MVP德凯文杜兰特"));
        player.add(new String("FMVP莱昂纳德"));
        player.add(new String("场均三双狂魔维斯布鲁克"));
        
        //统计书名包含“MVP”子串的图书数量
        System.out.println(player.stream().
                filter(ele -> ((String)ele).contains("MVP"))
                .count());            // 输出5
        //统计书名包含“FMVP”子串的图书数量
        System.out.println(player.stream().
                filter(ele -> ((String)ele).contains("FMVP"))
                .count());            // 输出2
        //统计书名字符串长度大于10的图书数量
        System.out.println(player.stream().
                filter(ele -> ((String)ele).length() > 10)
                .count());            // 输出2
        //先调用Collection对象的stream()方法将集合转换为Stream
        //再调用Stream的mapToInt()方法获取原有的Stream对应的IntStream
        player.stream().mapToInt(ele -> ((String)ele).length())
        //调用forEach()方法遍历IntStream中每个元素
        .forEach(System.out::println);            // 输出8.14.8.8.9.11
    }
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66383.html

相关文章

  • java集合

    摘要:主要用于遍历集合中的元素,对象也被称为迭代器。使用迭代过程中,不可修改集合元素迭代器采用快速失败机制。一旦迭代过程中检测到该集合已经被修改,程序立即出发异常,而不是显示修改后的结果,避免了共享资源而引发的潜在问题。 集合类和数组不一样,数组元素既可以是基本类型的值,也可以是对象(实际上保存的是对象的引用变量);而集合里只能保存对象(实际上只是保存对象的引用变量,但通常习惯上认为集...

    JinB 评论0 收藏0
  • 集合概要学习---粗略

    摘要:集合框架的基本接口类层次结构其中表示接口,表示实现类和在实际开发中,需要将使用的对象存储于特定数据结构的容器中。实例是迭代器,拥有两个方法方法迭代器用于遍历集合元素。返回值则是转换后的数组,该数组会保存集合中的所有元素。 Java Collections Framework是Java提供的对集合进行定义,操作,和管理的包含一组接口,类的体系结构。 Java集合框架的基本接口/类层次结构...

    DesGemini 评论0 收藏0
  • java集合--Collection接口

    摘要:集合的元素个数为输出集合的元素个数为在本代码中,新建一个局部变量保存的成员方法返回的值,输出得到因为只有一个元素。注若遍历集合的同时改变集合,将引发异常。     在概述里面也说过:Collection是java集合两大接口之一,旗下有三大子接口:Set(元素不能重复,且无序)、Queue、List(元素可重复,且有序)。    Collection来源于java.util包,主要方法...

    k00baa 评论0 收藏0
  • Java集合遍历

    摘要:集合的遍历使用主要用于遍历集合中的元素,因此创建的对象是一个迭代器。提供的四个方法如果迭代器的集合还没有被遍历完,返回。 集合的遍历 使用Iterator Iterator主要用于遍历集合中的Collection元素,因此Iterator创建的对象是一个迭代器。 Iterator提供的四个方法 boolean hasNext(): 如果迭代器的集合还没有被遍历完,返回ture。 Ob...

    MadPecker 评论0 收藏0
  • java集合和泛型的知识点归纳1

    摘要:接口也是集合中的一员,但它与接口有所不同,接口与接口主要用于存储元素,而主要用于迭代访问即遍历中的元素,因此对象也被称为迭代器。迭代器的实现原理我们在之前案例已经完成了遍历集合的整个过程。 【Collection、泛型】 主要内容 Collection集合 迭代器 增强for 泛型 教学目标 [ ] 能够说出集合与数组的区别 [ ] 说出Collection集合的常用功能 [ ]...

    daryl 评论0 收藏0

发表评论

0条评论

harryhappy

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<