`
ray_yui
  • 浏览: 220580 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

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
      数组与集合(2):http://ray-yui.iteye.com/blog/1930155
      枚举与注解:http://ray-yui.iteye.com/blog/1931408
      泛型与发射:http://ray-yui.iteye.com/blog/1933127
                  异常:http://ray-yui.iteye.com/blog/1938946
                      杂:http://ray-yui.iteye.com/blog/1942591


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


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


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

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种算法

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

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


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

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.对不同的数据结构使用不同的遍历方式
      请观看以下代码

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进行了复写,让我们在比较两个集合是否相等时,只需要比较元素数据是否相等即可,避免了因为替换集合实现类造成的错误

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建议》中提取部分进行归纳性叙述,推荐各位读者购买这本书,该书不仅从事例中学习,而且涉及到原理,底层的实现,不仅告诉你应该怎么做,还告诉你为什么要这样做.
23
15
分享到:
评论
8 楼 zjf201172653 2013-08-28  
powerful!非常有用!感谢!
7 楼 ray_yui 2013-08-26  
antique 写道
5.选择合适的最值算法的第一个例子是不是写错了啊

是的,非常感谢提醒,已修正
6 楼 antique 2013-08-26  
5.选择合适的最值算法的第一个例子是不是写错了啊
5 楼 hanxie1121 2013-08-23  
00000000000000000000000000000000000000000000000
4 楼 create_object 2013-08-23  
  
3 楼 桃花源记 2013-08-22  
希望楼主天天更新!
2 楼 steafler 2013-08-22  
    
1 楼 liudd5 2013-08-21  
   

相关推荐

    详解JAVA高质量代码之数组与集合

    在编程实践中,了解和掌握如何编写高质量的代码至关重要,尤其是对于Java这样的面向对象语言。本文主要探讨了在Java中处理数组和集合时的一些关键点,旨在提升编程效率和代码质量。 1. **性能考虑:优先选择数组** ...

    E4A易安卓视频教程源码: - 06、数组和集合.rar

    在本资源中,我们主要关注的是"E4A易安卓视频教程源码: - 06、数组和集合.rar",这是一份针对易安卓(EasyAndroid,简称E4A)编程语言的学习材料,特别是关于数组和集合的部分。易安卓是一个为非专业程序员设计的...

    java【第4章:数组与方法】_数组的引用传递.

    通过深入学习和实践,开发者能更好地控制程序的行为,编写出更高质量的代码。在后续的学习中,还会涉及到多维数组、数组作为方法返回值以及数组与集合框架的对比等更多相关内容,这些都是Java程序员必备的知识点。

    java教程 第五课 数组

    ### Java教程第五课:深入解析数组 #### 一、数组的概念与重要性 ...总之,数组是Java编程中非常重要的数据结构,熟练掌握数组的声明、创建、初始化、遍历以及多维数组的使用对于开发高质量的应用程序至关重要。

    Java 的常用包与数组的复制与排序26

    在Java编程语言中,了解和熟练使用常用的包以及掌握数组的复制与排序是成为Java开发者的必备技能。本文将深入探讨这两个关键知识点。 首先,Java的常用包是提供各种类和接口的基础,它们包含了实现特定功能的类库。...

    java泛型集合 java集合 集合 java Collection

    Java 泛型集合和Java集合框架是Java编程中不可或缺的部分,它们为开发者提供了高效的数据存储和操作机制。本文将深入探讨这两个主题,并...了解并熟练掌握这些概念和用法,对于提高Java编程效率和代码质量至关重要。

    java集合学习代码

    在这个“java集合学习代码”中,我们可能涵盖了一系列关于Java集合框架的核心概念和实践应用。 首先,Java集合框架包括接口和实现类。主要的接口有List、Set和Queue,它们都继承自Collection接口。List接口代表有序...

    如何执行Java代码审查

    Java 代码审查清单 一、代码整洁清单项分类 1. 使用有意义的名称:变量、函数和类名应该能够表达实际...本清单包含了代码整洁、安全、性能、综合和静态代码分析等方面的知识点,旨在帮助开发者编写高质量的Java代码。

    Java集合面试问题

    Java集合框架是Java平台的核心组件之一,它为开发者提供了多种数据结构来存储和操作对象集合。Java集合主要包括两大接口:`Collection` 和 `Map`。 #### Collection接口: - **特点**:它代表一个元素列表,可以...

    90个高质量的java问答.pdf

    以上只是部分知识点的概览,更多详细内容可参考《90个高质量的java问答.pdf》文档。这份资料对于准备 Java 技术面试的开发者来说非常宝贵,它涵盖了从基础到高级的多个主题,有助于全面理解和掌握 Java 编程语言的...

    Java初级课堂代码

    7. **方法与函数式编程**:编写可重用的方法是提升代码质量的关键。学习如何定义方法,理解参数传递,以及如何使用Java 8引入的函数式编程特性,如Lambda表达式,可以使代码更简洁、高效。 8. **调试与测试**:理解...

    Java集合框架总结

    ### Java集合框架总结 #### 一、Java集合框架概述 Java集合框架是Java标准库的一部分,它提供了一系列的接口和类来存储和操作各种类型的...同时,合理利用抽象类和迭代器等工具能够进一步提高代码的质量和可维护性。

    corejava12示例代码

    通过这些示例代码的学习,开发者可以更好地掌握Java的核心概念,并将其应用于实际项目中,提高开发效率和代码质量。记得实践是检验真理的唯一标准,理论学习的同时,务必动手实践,不断调试和完善代码。

    达内java学习源代码

    1. **Java基础**:这包括Java语言的基本语法,如变量、数据类型、运算符、控制结构(if-else、switch、循环)、方法、数组等。源代码可能包含了这些基本概念的实例。 2. **面向对象编程**:Java是一种面向对象的...

    Java集合框架使用总结

    ### Java集合框架使用总结 #### 一、概述 在Java编程中,集合框架是一个非常重要的概念,它提供了标准的方式来存储和操作...了解并熟练掌握这些概念和技术,对于提高编程效率和编写高质量的Java应用程序至关重要。

    Java实训 Java高级应用编程 第2章 集合(共33页).ppt

    - 与数组相比,集合具有动态扩展的能力,数组长度固定,而集合可以在运行时自动增长。 2. **集合框架层次结构**: - 集合框架的基础是`Collection`接口,它是所有单值集合的根接口。 - `Collection`接口有两个...

    Java集合框架培训资料

    Java集合框架是Java编程语言中的核心组件之一,它为数据存储和管理提供了丰富的类和接口。这个培训资料将深入探讨Java集合框架的各个方面,帮助开发者更有效地利用这些工具。 首先,我们要了解Java集合框架的基本...

    第13讲 JAVA集合类.ppt

    Java集合类是Java编程语言中用于存储和管理对象的关键组件,它们构成了Java Collections Framework的核心。这个框架提供了一组高效、灵活的数据...理解并熟练掌握这些集合类和接口,对于编写高质量的Java程序至关重要。

    java编程教程代码学习

    1. **基础语法**:包括数据类型、变量、运算符、流程控制(条件语句和循环)、数组和字符串等。 2. **面向对象编程(OOP)**:Java是一种面向对象的语言,理解类、对象、继承、封装、多态和抽象等概念至关重要。 3. **...

Global site tag (gtag.js) - Google Analytics