您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

开发人员和程序员如何利用Java集合?

时间:2022-09-23 10:26:46  来源:今日头条  作者:小马搞编程

本文讨论了 JAVA Collections Framework 背后的目的、Java 集合的工作原理,以及开发人员和程序员如何最大限度地利用 Java 集合。

什么是 Java 集合

尽管 Java 已经过了 25 岁生日,仍然是当今最受欢迎的编程语言之一。超过 100 万个网站通过某种形式在使用 Java,超过 三分之一 的软件开发人员的工具箱中有 Java。

Java 在它的整个生命历程中经历了重大的演变。一个早期的进步出现在 1998 年,当时 Java 引入了 Collections Framework(Java Collection Framework,JCF),简化了操作 Java 对象的任务。JCF 为集合提供了标准化的接口和通用方法,减少了编程工作,并提升了 Java 程序的运行速度。

理解 Java 集合和 Java Collections Framework 之间的区别是至关重要的。Java 集合只是表示一组 Java 对象的数据结构。开发人员可以像处理其他数据类型一样处理集合,执行搜索或操作集合内容等常见任务。

Set 接口(java.util.Set)就是 Java 集合的一个例子。Set 是一种集合,不允许出现重复元素,也不以任何特定的顺序存储元素。Set 接口继承了 Collection(java.util.Collection)的方法,并且只包含这些方法。

除了集合之外,还有队列(java.util.Queue)和 Map(java.util.Map)。Map 并不是真正意义上的集合,因为它们没有 继承集合接口 ,但开发人员可以像操作集合一样操作 Map。集合、队列、列表和 Map 都有后代,比如排序集合(java.util.SortedSet)和可导航 Map(java.util.NavigableMap)。

在使用集合时,开发人员需要熟悉和理解一些特定的集合相关术语。

  • 可修改与不可修改——正如这些术语表面上所表明的,不同的集合可能支持也可能不支持修改操作。
  • 可变集合与不可变集合——不可变集合在创建后不能被修改。虽然在某些情况下,不可修改的集合仍然可能由于其他代码的访问而发生变化,但不可变集合会阻止这种变更。不可变集合是指能够保证 Collection 对象中不会有任何变更的集合,而不可修改的集合是指不允许“add”或“clear”等修改操作的集合。
  • 固定大小与可变大小——这些术语仅与集合的大小有关,与集合是可修改还是可变无关。
  • 随机访问与顺序访问——如果一个集合允许为每一个元素建立索引,那么它就是可随机访问的。在顺序访问集合中,必须通过所有前面的元素到达指定的元素。顺序访问集合更容易扩展,但搜索时间更长。初学者可能会难以理解不可修改集合和不可变集合之间的区别。不可修改集合不一定是不可变的。实际上,不可修改集合通常是可修改集合的包装器,其他代码仍然可以访问和修改被包装的可修改集合。通常需要使用集合一些时间才能在一定程度上理解不可修改集合和不可变集合。

例如,我们将创建一个可修改的按市值排名前五的加密货币列表。你可以使用
java.util.Collections.unmodifiableList()方法创建底层可修改列表的不可修改版本。你仍然可以修改底层列表,它只是被包装成不可修改列表,但你不能直接修改不可修改的版本。

import java.util.*;
public class UnmodifiableCryptoListExample {  
    public static void mAIn(String[] args) {  


        List<String> cryptoList = new ArrayList<>();  
        Collections.addAll(cryptoList, "BTC", "ETH", "USDT", "USDC", "BNB");  
        List<String> unmodifiableCryptoList = Collections.unmodifiableList(cryptoList);  
        System.out.println("Unmodifiable crypto List: " + unmodifiableCryptoList);  


        // 尝试在可修改列表中再添加一种加密货币,并显示在不可修改列表中
        cryptoList.add("BUSD");
        System.out.println("New unmodifiable crypto List with new element:" + unmodifiableCryptoList);


        // 尝试添加并显示一个额外的加密货币到不可修改列表中——unmodifiableCryptoList.add将抛出一个未捕获的异常,println代码将无法被执行
        unmodifiableCryptoList.add("XRP");
        System.out.println("New unmodifiable crypto List with new element:" + unmodifiableCryptoList);


        }  
}

复制代码

在运行代码时,你将看到对底层可修改列表添加的内容显示为对不可修改列表的修改。

但这与你创建了一个不可变列表并试图修改底层列表不同。有许多种方法可以基于现有的 可修改列表创建不可变列表 ,下面我们使用 List.copyOf()方法创建了一个不可变列表。

import java.util.*;
public class UnmodifiableCryptoListExample {  
    public static void main(String[] args) {  


        List<String> cryptoList = new ArrayList<>();  
        Collections.addAll(cryptoList, "BTC", "ETH", "USDT", "USDC", "BNB");
        List immutableCryptoList = List.copyOf(cryptoList);
        System.out.println("Underlying crypto list:" + cryptoList)
        System.out.println("Immutable crypto ist: " + immutableCryptoList);  


        // 尝试添加更多的加密货币到可修改列表,但不可变列表并没有显示变化
        cryptoList.add("BUSD");
        System.out.println("New underlying list:" + cryptoList);
        System.out.println("New immutable crypto List:" + immutableCryptoList);


        // 尝试添加并显示一个新的加密货币到不可修改的列表中
        immutableCryptoList.add("XRP");
        System.out.println("New unmodifiable crypto List with new element:" + immutableCryptoList);


        }  
}

复制代码

修改底层的列表后,不可变列表不显示变更。尝试修改不可变列表会直接导致抛出
UnsupportedOperationException。

 

集合与 Java Collections Framework 的关系

在引入 JCF 之前,开发人员可以使用几个特殊的类,即 Array、Vector 和 Hashtable。但这些类有很大的局限性,除了缺乏公共接口之外,它们还难以扩展。

JCF 提供了一个用于处理集合的通用架构。集合接口包含了几个不同的组件。

  • 公共接口——主要集合类型的表示,包括集合、列表和 Map;
  • 实现——集合接口的特定实现,从通用得到特殊的再到抽象的。此外,还有一些与旧的 Array、Vector 和 Hashtable 类相关的遗留实现;
  • 算法——用于操作集合的静态方法;
  • 基础结构——对各种集合接口的底层支持。与之前相比,JCF 为开发人员提供了许多好处。值得注意的是,JCF 降低了开发人员对自己编写数据结构的需求,从而提高了 Java 编程的效率。

但是,JCF 也从根本上改变了开发人员使用 API 的方式。JCF 通过提供一组新的公共接口来处理不同的 API,简化了开发人员学习、设计和实现 API 的过程。此外,API 的互操作性也大大提升了。 Eclipse Collections就是一个例子 ,它是一个完全兼容不同 Java 集合类型的开源 Java 集合库。

由于 JCF 提供了更容易重用代码的结构,从而进一步提升了开发效率。其结果就是开发时间缩短了,程序质量也得到了提升。

JCF 有一个定义良好的接口层次结构。java.util.Collection 扩展了超接口 Iterable,Collection 有许 多子接口和子类 ,如下所示。

 

如前所述,集合是唯一性对象的无序容器,而列表是可能包含重复项的有序集合。你可以在列表中的任何位置添加元素,但其他部分仍然保留了顺序。

队列也是集合,元素被添加到一端,并在另一端被删除。也就是说,它是一种先进先出(FIFO)接口。Deque(双端队列)允许从任意一端添加或删除元素。

使用 Java 集合的方法

JCF 中的每一个接口,包括 java.util.Collection,都提供了特定的方法用于访问和操作集合的各个元素。集合提供的常用的方法有:

  • size()——返回集合中元素的个数;
  • add(Collection element) / remove(Collection object)——这些方法用于修改集合的内容。需要注意的是,当集合中有重复元素时,移除只会影响元素的单个实例;
  • equals(Collection object)——比较对象与集合是否等价;
  • clear()——删除集合中的所有元素。每个子接口也可以有其他方法。例如,尽管 Set 接口只包含来自 Collection 接口的方法,但 List 接口包含了许多用于访问特定列表元素的方法。
  • get(int index)——返回指定索引位置的元素;
  • set(int index, element)——设置指定索引位置的元素;
  • remove(int,index)——移除指定索引位置的元素。

Java 集合的性能

随着集合元素数量的增长,它们可能会出现明显的性能问题。事实证明, 集合类型的选择 和集合的相关设计也会极大地影响集合的性能。

随着需要处理的数据量不断增加,Java 引入了新的处理集合的方法来提升整体性能。在 2014 年发布的 Java 8 引入了 Streams——旨在简化和提高批量处理对象的速度。自从推出以来,Streams 已经有了许多 改进 。

需要注意的是,流本身并不是数据结构,而是“对流中的元素进行函数式操作(例如对集合进行 map-reduce 转换)的类。”

Streams 使用方法管道来处理从数据源(如集合)接收到的数据。Streams 的每一个方法要么是一个中间方法(返回可以进一步处理的流),要么是一个终端方法(在此之后不可能进行其他流处理)。管道中的中间方法是惰性的,也就是说,它们只在必要时才进行求值。

并行执行和 串行执行 都存在于流中。默认情况下,流是串行的。

 

通过并行处理来提升性能

在 Java 中处理大型集合可能很麻烦。虽然 Streams 简化了大型集合的处理和编码工作,但并不总是能保证性能上的提升。事实上,程序员经常发现使用 Streams 反而会 减慢处理速度 。

众所周知,网站用户只会等待几秒钟的加载时间,然后他们就会离开。因此,为了提供最好的用户体验并 维护开发人员 提供高质量产品的声誉,开发人员必须考虑如何优化大型数据集合的处理。虽然并行处理并不总能保证提高速度,但至少是有希望的。

并行处理,即将处理任务分解为更小的块并同时执行它们,提供了一种在处理大型集合时减少处理开销的方法。但是,即使并行流处理简化了代码编写,也会 导致性能下降 。本质上,多线程管理开销会抵消并行运行线程所带来的好处。

因为集合不是线程安全的,并行处理可能会导致线程干扰或内存不一致(当并行线程看不到其他线程所做的修改,对相同的数据有不同的视图时)。Collections Framework 试图通过使用同步包装器在并行处理期间防止线程不一致。虽然包装器可以让集合变成线程安全的,从而实现更高效的并行处理,但它可能会产生不良的性能影响。具体来说,同步可能会导致线程争用,从而导致线程执行得更慢或停止执行。

Java 有一个用于集合的元素并行处理函数 Collection.parallelstream。默认的串行处理和并行处理之间的一个显著区别是,串行处理时总是相同的执行和输出顺序在并行处理时可能会有不同。

因此,在处理顺序不影响最终输出的场景中,并行处理会特别有效。但是,在一个线程的状态可能会影响另一个线程状态的场景中,并行处理可能会有问题。

我们来考虑一个简单的示例,在这个示例中,我们为包含 1000 个客户创建了一个应收账款列表。我们想要知道这些客户中有多少人的应收账款超过 25000 美元。我们可以按照串行或并行的处理方式检查这个列表。

import java.util.Random;
import java.util.ArrayList;
import java.util.List;


class Customer {


    static int customernumber;
    static int receivables;


    Customer(int customernumber, int receivables) {
        this.customernumber = customernumber;
        this.receivables = receivables;
    }


    public int getCustomernumber() {
        return customernumber;
    }


    public void setCustomernumber(int customernumber) {
        this.customernumber = customernumber;
    }


    public int getReceivables() {
        return receivables;
    }


    public void setReceivables() {
        this.receivables = receivables;
    }
}


public class ParallelStreamTest {


    public static void main( String args[] ) {


        Random receivable = new Random();


        int upperbound = 1000000;
   
            List < Customer > custlist = new ArrayList < Customer > ();


                for (int i = 0; i < upperbound; i++) {
    
                    int custnumber = i + 1;
                    int custreceivable = receivable.nextInt(upperbound);
                    custlist.add(new Customer(custnumber, custreceivable));
                 
 }


long t1 = System.currentTimeMillis();


                System.out.println("Sequential Stream count: " + custlist.stream().filter(c ->
c.getReceivables() > 25000).count());


                long t2 = System.currentTimeMillis();


                System.out.println("Sequential Stream Time taken:" + (t2 - t1));


               t1 = System.currentTimeMillis();


                System.out.println("Parallel Stream count: " + custlist.parallelStream().filter(c ->
c.getReceivables() > 25000).count());


                 t2 = System.currentTimeMillis();


                 System.out.println("Parallel Stream Time taken:" + (t2 - t1));


    }


}

复制代码

代码执行结果表明,在处理数据集合时, 并行处理 可能会提升性能:

 

但需要注意的是,每次执行代码时,你可能获得不同的结果。在某些情况下,串行处理仍然优于并行处理。

 

在本例中,我们使用 Java 的原生进程来分割数据和分配线程。

不幸的是,对于上述两种情况,Java 的原生并行处理并不总是比串行处理更快。实际上,经常会更慢。

例如,并行处理对于链表没有什么用。虽然 ArrayList 很容易被分割成并行处理,但 LinkedList 却不是这样的。TreeMap 和 HashSet 介于两者之间。

Oracle 的 NQ模型 是决定是否使用并行处理的一种方法。在 NQ 模型中,N 表示需要处理的数据元素数量,Q 表示每个数据元素所需的计算量。在 NQ 模型中,计算 N 和 Q 的乘积,数值越大,说明并行处理提高性能的可能性越大。

在使用 NQ 模型时,N 和 Q 之间存在反比关系,即每个元素所需的计算量越高,并行处理的数据集就越小。经验法则是,对于较低的计算需求,包含 10000 个元素的数据集是使用并行处理的基线。

除此之外,还有其他更高级的方法来优化 Java 集合中的并行处理。例如,高级开发人员可以调整集合中数据元素的分区,以最大化并行处理性能。还有一些 第三方的JCF插件 和替代品可以提升性能。但是,初学者和中级开发人员应该重点了解哪些操作可以从 Java 的原生并行处理特性中受益。

结论

在大数据世界里,想要创建高性能的网页和应用程序,必须找到改进大量数据处理的方法。Java 提供了内置的集合处理特性帮助开发人员改进数据处理,包括 Collections Framework 和原生并行处理功能。开发人员需要熟悉如何使用这些特性,并了解可以时候可以使用原生特性,什么时候应该使用并行处理。

作者简介:

Nahla Davies 是一名软件开发人员和技术作家。在全职从事技术写作之前,她曾在一家体验式品牌企业担任首席程序员,该组织的客户包括三星、时代华纳.NETflix 和索尼。

原文链接:

https://www.infoq.com/articles/java-collections-streams/



Tags:Java集合   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Java集合框架解析:选择正确数据结构提升性能
Java集合框架是Java编程中不可或缺的一部分,它提供了一组用于存储和操作数据的类和接口。在使用集合框架时,选择正确的数据结构非常重要,可以显著提升程序的性能和效率。下面将...【详细内容】
2023-09-05  Search: Java集合  点击:(315)  评论:(0)  加入收藏
你的Java集合线程安全吗?快来检查一下!
Java线程安全的集合 简介在多线程编程中,使用线程安全的集合是非常重要的,它可以保证多个线程同时访问同一个集合时,不会出现数据不一致的情况。Java 中提供了多种线程安全的...【详细内容】
2023-05-06  Search: Java集合  点击:(334)  评论:(0)  加入收藏
开发人员和程序员如何利用Java集合?
本文讨论了 Java Collections Framework 背后的目的、Java 集合的工作原理,以及开发人员和程序员如何最大限度地利用 Java 集合。什么是 Java 集合尽管 Java 已经过了 25 岁...【详细内容】
2022-09-23  Search: Java集合  点击:(392)  评论:(0)  加入收藏
你每天都在用的Java集合框架,您真的懂吗?
Java集合框架一、集合框架概况类图List、Set、Map的区别: - List:存储的元素是有序的,可重复的。 - Set:存储的元素是无序的,不可重复的。 - Map:使用键值对(key-value)存储...【详细内容】
2022-05-07  Search: Java集合  点击:(375)  评论:(0)  加入收藏
Java集合-Iterator
Java Iterator接口表示一个对象,该对象能够遍历Java对象的集合,一次迭代一个对象。Iterator 接口是Java中用于迭代对象集合的最古老的机制之一(尽管不是最早的-Enumerator 早于...【详细内容】
2020-08-31  Search: Java集合  点击:(203)  评论:(0)  加入收藏
Java集合的常见用法你知道多少?
一、集合与数组的区别相同点:都是用来存储数据的。不同点:1.集合带array的,底层由数组实现,还有一部分由其他方式(树、链表等)实现。2.数组大小固定,而集合没有固定的大小,更方便...【详细内容】
2020-06-04  Search: Java集合  点击:(266)  评论:(0)  加入收藏
Java集合详解
集合类简述在没有集合类之前,实际上在Java语言里已经有一种方法可以存储对象,那就是数组。数组不仅可以存放基本数据类型也可以容纳属于同一种类型的对象。数组的操作是高效率...【详细内容】
2020-03-01  Search: Java集合  点击:(311)  评论:(0)  加入收藏
Java集合之深度剖析集合架构
一些大公司面试总会问一些Java集合相关的知识,如ArrayList实现原理、HashMap实现原理等。所以作者准备做一个针对Java集合进行剖析的专题(后续几篇文章会全部围绕Java集合展开)。...【详细内容】
2019-12-17  Search: Java集合  点击:(484)  评论:(0)  加入收藏
不得不学的java集合框架
一、Java集合框架概述集合可以看作是一种容器,用来存储对象信息。所有集合类都位于java.util包下,但支持多线程的集合类位于java.util.concurrent包下。数组与集合的区别如下:1...【详细内容】
2019-11-06  Search: Java集合  点击:(532)  评论:(0)  加入收藏
▌简易百科推荐
Java 8 内存管理原理解析及内存故障排查实践
本文介绍Java8虚拟机的内存区域划分、内存垃圾回收工作原理解析、虚拟机内存分配配置,以及各垃圾收集器优缺点及场景应用、实践内存故障场景排查诊断,方便读者面临内存故障时...【详细内容】
2024-03-20  vivo互联网技术    Tags:Java 8   点击:(15)  评论:(0)  加入收藏
如何编写高性能的Java代码
作者 | 波哥审校 | 重楼在当今软件开发领域,编写高性能的Java代码是至关重要的。Java作为一种流行的编程语言,拥有强大的生态系统和丰富的工具链,但是要写出性能优异的Java代码...【详细内容】
2024-03-20    51CTO  Tags:Java代码   点击:(24)  评论:(0)  加入收藏
在Java应用程序中释放峰值性能:配置文件引导优化(PGO)概述
译者 | 李睿审校 | 重楼在Java开发领域,优化应用程序的性能是开发人员的持续追求。配置文件引导优化(Profile-Guided Optimization,PGO)是一种功能强大的技术,能够显著地提高Ja...【详细内容】
2024-03-18    51CTO  Tags:Java   点击:(27)  评论:(0)  加入收藏
Java生产环境下性能监控与调优详解
堆是 JVM 内存中最大的一块内存空间,该内存被所有线程共享,几乎所有对象和数组都被分配到了堆内存中。堆被划分为新生代和老年代,新生代又被进一步划分为 Eden 和 Survivor 区,...【详细内容】
2024-02-04  大雷家吃饭    Tags:Java   点击:(57)  评论:(0)  加入收藏
在项目中如何避免和解决Java内存泄漏问题
在Java中,内存泄漏通常指的是程序中存在一些不再使用的对象或数据结构仍然保持对内存的引用,从而导致这些对象无法被垃圾回收器回收,最终导致内存占用不断增加,进而影响程序的性...【详细内容】
2024-02-01  编程技术汇  今日头条  Tags:Java   点击:(70)  评论:(0)  加入收藏
Java中的缓存技术及其使用场景
Java中的缓存技术是一种优化手段,用于提高应用程序的性能和响应速度。缓存技术通过将计算结果或者经常访问的数据存储在快速访问的存储介质中,以便下次需要时可以更快地获取。...【详细内容】
2024-01-30  编程技术汇    Tags:Java   点击:(73)  评论:(0)  加入收藏
JDK17 与 JDK11 特性差异浅谈
从 JDK11 到 JDK17 ,Java 的发展经历了一系列重要的里程碑。其中最重要的是 JDK17 的发布,这是一个长期支持(LTS)版本,它将获得长期的更新和支持,有助于保持程序的稳定性和可靠性...【详细内容】
2024-01-26  政采云技术  51CTO  Tags:JDK17   点击:(90)  评论:(0)  加入收藏
Java并发编程高阶技术
随着计算机硬件的发展,多核处理器的普及和内存容量的增加,利用多线程实现异步并发成为提升程序性能的重要途径。在Java中,多线程的使用能够更好地发挥硬件资源,提高程序的响应...【详细内容】
2024-01-19  大雷家吃饭    Tags:Java   点击:(107)  评论:(0)  加入收藏
这篇文章彻底让你了解Java与RPA
前段时间更新系统的时候,发现多了一个名为Power Automate的应用,打开了解后发现是一个自动化应用,根据其描述,可以自动执行所有日常任务,说的还是比较夸张,简单用了下,对于office、...【详细内容】
2024-01-17  Java技术指北  微信公众号  Tags:Java   点击:(99)  评论:(0)  加入收藏
Java 在 2023 年仍然流行的 25 个原因
译者 | 刘汪洋审校 | 重楼学习 Java 的过程中,我意识到在 90 年代末 OOP 正值鼎盛时期,Java 作为能够真正实现这些概念的语言显得尤为突出(尽管我此前学过 C++,但相比 Java 影响...【详细内容】
2024-01-10  刘汪洋  51CTO  Tags:Java   点击:(78)  评论:(0)  加入收藏
站内最新
站内热门
站内头条