`

Java高质量代码-集合和数组(1)

    博客分类:
  • JAVA
阅读更多
前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间拜读了秦小波老师的《改善Java程序的151建议》,感觉廓然开朗,注意到了很多平时在编写代码中并不会注意的问题,甚至感觉自己对Java只是略懂皮毛,不足以登大雅之堂,特此与读者分享读书笔记,以下内容摘自《改善Java程序的151建议》一书和笔者的理解


Java高质量代码系列文章
      面向对象篇:http://ray-yui.iteye.com/blog/1926984
      数据类型篇:http://ray-yui.iteye.com/blog/1927251
          字符串篇:http://ray-yui.iteye.com/blog/1927647
      数组与集合(1):http://ray-yui.iteye.com/blog/1928170


      还记得当初学习编程的时候,老师曾经说过,什么是程序?就是数据结构加算法,这句话当时并没有多大的体会,对编程逐渐熟悉后,回想起来,确实如此,而在Java中的数据结构,就体现在集合框架当中,而使用集合有哪些地方需要注意呢?


1.性能考虑,优先选择数组
      数组在项目开发当中使用的频率是越来越少,特别是在业务为主的开发当中,首先数组没有List,Set等集合提供的诸多方法,查找增加算法都要自己编写,极其繁琐麻烦,但由于List,Set等集合使用泛型支持后,存放的都为包装类,而数组是可以使用基本数据类型,而使用基本数据类型的执行运算速度要比包装类型快得多,而且集合类的底层也是通过数组进行实现.


2.若有必要,使用变长数组
      在学习集合类当中,很多人喜欢将数组的定长拿来和集合类型的自变长来做比较,但其实这种比较并不合适,通过观察集合类例如ArrayList的实现其实可以看出,所谓的集合变长,其实只是用婉转的方式对原数组进行了扩容

Java代码  收藏代码
public static <T> T[] expandCapacity(T[] data, int newLength) { 
        // 判断是否为负值 
        newLength = newLength < 0 ? 0 : newLength; 
 
        // 生成新数组,拷贝原值并制定长度 
        return Arrays.copyOf(data, newLength); 
    } 


      当性能要求高的时候,可以考虑使用对数组进行封装使用,数组长度不变不是我们不使用它们的借口


3.警惕数组的浅拷贝
      数组的浅拷贝在Java编程中亦是基础中的基础,浅拷贝是在为数组拷贝时,基本类型拷贝的是值,而引用类型拷贝的是引用地址,在上面的例子当中,拷贝数组使用的Arrays.copyOf为浅拷贝,在使用时需要注意


4.在明确的场景下,为集合指定初始容量
      在我们平常的使用当中,因为集合类型是自动变长的,所以基本创建对象时不会为集合类附上初始值,就拿我们最常用的ArrayList来说明,我们首先要知道,当集合容量到达临界点时,会将底层的数组进行copyOf的操作,生成新的数组,而新的数组容量为旧数组的1.5倍,而默认数组长度为10,当我们明确知道要放置入容器中的数据数量较多时,应该指明初始值,避免多次使用copyOf造成的性能开销


5.选择合适的最值算法
      对数据进行最大值或最小值的查找,这是数据结构最基本的知识,在Java当中我们亦有很多种的方式进行实现,以下列举2种算法

Java代码  收藏代码
public static int getMaxByArray(int[] data) { 
        // 最简单自行实现的查找方式 
        int max = data[0]; 
        for (int i = 1, size = data.length; i < size; i++) { 
            max = max < i ? i : max; 
        } 
        return max; 
    } 

Java代码  收藏代码
public static int getMaxByArray(int[] data) { 
        // 先排序后获取最后位 
        Arrays.sort(data); 
        return data[data.length - 1]; 
    } 


6.基本类型数组转换陷阱!
      请观察以下代码

Java代码  收藏代码
public static void main(String[] args) { 
        int[] nums = new int[] { 1, 2, 3, 4, 5 }; 
        List list = Arrays.asList(nums); 
        System.out.println(list.size()); 
        // 此时输出的size为1 
    } 


      我们期望的结果是将数组中的元素通过Arrays.asList转换到集合类当中,但事与愿违,我们只将数组本身增加了进入,并没有将数组内的值分拆分开来,此时若然对集合List增加了泛型就会在编译期间给出错误的提示,或将数组本身改变成Integer就可以解决问题     


7.asList方法产生的List对象不可更改
      通过上面的例子,我们可以看到使用Arrays.asList方法可以将一个数组转换成一个List,那通过asList方法返回的List有什么特别呢?注意,这个返回的List是不支持更改的,原因是因为asList方法返回的,并不是java.util.ArrayList,而是Arrays工具类中的一个静态私有内部类,虽然都有实现和ArrayList一样的父类AbstractList,但在复写add等方法时,却是抛出了UnsupportedOperationException,
这个静态私有内部类只实现了size,toArray,get,contains这几个方法


8.对不同的数据结构使用不同的遍历方式
      请观看以下代码

Java代码  收藏代码
public static void main(String[] args) { 
        // 以下为ArrayList集合的遍历方式 
        int num = 80 * 10000; 
        List<Integer> arrayList = new ArrayList<Integer>(num); 
        for (int i = 0, size = arrayList.size(); i < size; i++) { 
            arrayList.get(i); 
        } 
 
        // 以下为LinkedList集合的遍历方式 
        List<Integer> linkedList = new LinkedList<Integer>(); 
        for (Integer integer : linkedList) { 
 
        } 
    } 


      为什么对LinkedList和ArrayList要选择不同的遍历方式?

      1.因为ArrayList实现了RamdomAccess接口(随机存取接口),RamdomAccess
        接口和Serializable,Cloneable接口一样是Java中的标示接口,代表这个
        这个类可以随机存取,对ArrayList来说就标志着,数据之间没有关联,
        即相邻的两个位置没有互相依赖的关系,可以随机访问,

      2.Java中的foreach语法是iterator(迭代器)的变形用法,我们知道迭代器
        是23种设计模式的一种,但迭代器是需要知道两个元素时间的关系的,不然
        怎么提供hasNext的支持呢?就是因为上一个元素要判断下一个元素是否
        存在,强行建立了这种关系,违背了ArrayList随机存取的特别

      3.在LinkedList中,因为是通过双向链表的形式来存储,所以对迭代器的
        支持非常好,因为LinkedList相邻的两个元素本来就存在关系

      所以在对LinkedList和ArrayList要采取不同的遍历方式,读者若然有兴趣
      可以尝试一下对LinkedList采用下标的形式访问,会发现两者的效率有较大
      的差距


8.适时选择ArrayList或LinkedList
      ArrayList和LinkedList的主要区别:

      1.ArrayList底层的数据结构为数组,而LinkedList底层结构为双向链表

      2.在插入数据时,由于ArrayList每次插入后都需要将数组元素向后顺延
        位置,而LinkedList只需要更改头节点和尾节点即可完成插入操作,所以
        在插入操作较为频繁时,优先使用LinkedList

      3.在删除数据时,由于ArrayList要保持数组的有序性,当删除后元素要亦
        需要向后或向前移位,而LinkedList照旧还是更改头尾节点.

      4.在更新时,由于LinkedList会使用折半遍历的方式进行查找定位元素再
        进行更新,对比起ArrayList的直接定位下表元素替换,ArrayList对更新
        的的效率更佳

      5.LinkedList可以模拟队列,通过LinkedList的addFirst,addLast等操作


9.列表相等只需关心元素数据
      Java为了我们可以安心的面向List,Set,Map等接口进行编程,因此对集合类中的equlas进行了复写,让我们在比较两个集合是否相等时,只需要比较元素数据是否相等即可,避免了因为替换集合实现类造成的错误

Java代码  收藏代码
public static void main(String[] args) { 
        List<Integer> arrayList = new ArrayList<Integer>(); 
        arrayList.add(1); 
        arrayList.add(2); 
 
        List<Integer> linkedList = new LinkedList<Integer>(); 
        linkedList.add(1); 
        linkedList.add(2); 
 
        System.out.println(arrayList.equals(linkedList)); 
        // 不用关心具体实现,输出为true 
    } 


总结:
      笔者在本文章中只从《改善Java程序的151建议》中提取部分进行归纳性叙述,推荐各位读者购买这本书,该书不仅从事例中学习,而且涉及到原理,底层的实现,不仅告诉你应该怎么做,还告诉你为什么要这样做.
分享到:
评论

相关推荐

    Java基础精品课17-集合框架.zip

    最后,面试中经常涉及的题目包括:集合框架的实现原理、集合的遍历方式、集合和数组的转换、集合的线程安全问题、以及不同集合类之间的性能对比等。通过本课程的学习,开发者能够熟练运用Java集合框架,提高代码质量...

    java代码-集合类型,返回值为对象时。

    8. **集合与数组的转换**:有时需要在集合和数组之间转换。可以使用`toArray()`方法将集合转换为数组,或者通过`Arrays.asList()`将数组转换为列表。 9. **集合的拷贝**:为了防止对原始集合的修改,可以创建集合的...

    java 集合框架的原理及其使用

    Java集合框架是Java编程语言中一个非常重要的组成部分,它为开发者提供了存储和管理对象的统一方式。这个框架包括了一系列接口、抽象类以及实现...理解并熟练使用这些集合类和接口,对于编写高质量的Java代码至关重要。

    learn-java-master_java_知识点_

    1. **基础语法**:Java的基础包括变量、数据类型(如整型、浮点型、字符型和布尔型)、运算符(算术、关系、逻辑等)、流程控制(if语句、switch语句、for循环、while循环)和数组。理解这些基本元素是编写Java代码...

    Java课程设计案例精编(源代码)

    - **变量与数据类型**:Java提供了基本数据类型,如整型、浮点型、字符型和布尔型,以及引用数据类型,如类、接口和数组。案例中可能会展示如何声明和使用这些类型。 - **控制流**:包括条件语句(if-else)、循环...

    Java 72道面试题和答案.docx

    理解这些核心概念和实现细节对于深入掌握Java集合框架至关重要,它们可以帮助开发者在实际开发中选择合适的集合类型,优化性能,并编写出高质量的代码。在面试中,能够清晰地解释这些概念并给出具体应用场景,将展示...

    SUN-JAVA-SCJP认证考试

    通过SCJP认证,证明了考生具备编写高质量、可维护的Java程序的能力。 模块5(Module5.pdf)通常涵盖了Java类和对象的深入理解,包括封装、继承、多态性等面向对象特性。在这个模块中,考生会学习如何创建和使用类,...

    2020老杜最新版Java零基础进阶视频教程-面向对象课件

    通过上述知识的学习,无论是Java初学者还是有经验的开发者,都能深入理解Java的核心概念,并能够构建和维护高质量的Java应用程序。在实际开发中,这些基础知识将为解决问题和优化代码提供坚实的基础。

    java核心技术所有版本源代码下载地址

    这本书分为两卷,第一卷主要关注基础知识,如语法、面向对象编程、异常处理、字符串处理、集合和数组;第二卷则深入到高级主题,如多线程、网络编程、I/O、数据库访问以及Swing图形用户界面。 在提供的链接中...

    Java集合面试题 52道.pdf

    集合和数组的区别 数组和集合的主要区别在于:数组是固定长度的,集合是可变长度的;数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型;数组存储的元素必须是同一个数据类型,集合存储...

    java技术手册(第6版)

    - **使用Java集合和数组**:介绍Java标准库中的集合框架,包括List、Set、Map等接口及其具体实现类,以及数组的操作。 - **处理常见数据格式**:讲解如何处理XML、JSON等常用数据交换格式,以及如何使用Java内置...

    java学习问题及聊天代码

    - 变量与数据类型:Java支持基本数据类型(如int、double、char)以及引用数据类型(如类、接口和数组)。理解它们的区别是学习Java的第一步。 - 控制流:包括条件语句(if-else)、循环语句(for、while、do-...

    JAVA5-6新特性列表.doc

    6. **新的迭代语句**:Java 5引入了for-each循环,简化了遍历集合和数组的操作,如`for (String s : strings) {...}`。 7. **静态导入**:允许导入一个类的所有静态成员,如`import static java.util.Arrays.*;`,...

    java知识点总结学习

    以上知识点构成了Java学习的基础,熟练掌握这些内容能够帮助开发者构建高质量的Java应用和Web服务。对于`mianshi题集合.xlsx`,它可能是一个包含Java题目或者面试问题的Excel文件,用于检验和提升学习效果。在学习...

    Java语言规范宝典

    对于初学者来说,理解并遵循这些规范至关重要,因为它们能够帮助新进开发者构建出高质量的软件。下面,我们将深入探讨Java语言规范中的关键知识点。 1. **命名规范**: - 类名:使用大驼峰命名法,每个单词首字母...

    Java课件,Java课件

    Java提供了两种主要的数据类型:基本类型(如int、float、char)和引用类型(如类、接口和数组)。变量用于存储数据,而运算符则用于执行计算或逻辑操作。控制结构如if语句、for循环和while循环是程序流程控制的关键...

    Java开发JDK,jdk1.6(JDK6)

    - **增强的for循环(Enhanced For Loop)**:也被称为foreach循环,简化了遍历集合和数组的操作,使代码更加简洁。 - **动态代理(Dynamic Proxies)**:提供了创建动态代理类的能力,允许在运行时构建实现一组接口的...

Global site tag (gtag.js) - Google Analytics