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

Java高质量代码之 — 数组与集合(2)

    博客分类:
  • 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


好吧,本来是非常繁忙的星期五,但笔者公司的DB服务器又down了,文章时间又来了,上一章由于时间限制只讲了一半,下面继续书接上回


10.子列表只是原列表的视图
      List接口中,提供了subList方法,作用就是返回一个列表中的子列表,这个方法与String类型的substring有点类似,请观察以下代码

public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(2);
		List<Integer> subList = list.subList(0, 2);
		System.out.println(subList); // 输出为1,2
		subList.add(3); // 子列表增加元素
		System.out.println(list); // 输出原列表,输出为1,2,3
	}


      我们可以把List接口中的subList想成和数据库中的视图一样,在数据库中虽然不建议我们对视图进行增删改,但确实是可以操作的,而且操作完也可以反映到表当中,subList也同理,它只是原列表的视图,所有的操作都将直接影响原列表,但subList和数据库视图有一点不同,下面将会进行说明


11.推荐使用subList处理局部列表
      现在有一个需求,在一个长度为50的列表中删除位置是10~20的元素

public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>();
		// 增加50行
		for (int i = 0, size = 50; i < size; i++) {
			list.add(i);
		}
		
		// 方法1
		for (int i = 10; i < 20; i++) {
			list.remove(10);
		}
		
		// 方法2
		list.subList(10, 20).clear();
		System.out.println(list);
	}


      以上方法2,为什么要不停删除位置为10的元素呢?这是很容易忽略的问题,因为List当删除元素时,为了保持有序性,会移动元素替换被删除的位置,所以当位置为10的元素删除后,11的位置会替换上来..在上面已经提到,修改子列表会直接影响原列表,使用方法2的一行就能完成,是不是很方便?


12.生成子列表后不要再操作原列表
      subList生成子列表是原列表的视图,而对子列表的改动会直接影响原列表,那若然是对原列表的更改呢?

public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(2);
		List<Integer> subList = list.subList(0, 2);
		// 原列表增加数据
		list.add(3);
		// 对比元素数量
		System.out.println(list.size() == subList.size());

		// 运行结果,抛出java.util.ConcurrentModificationException异常
	}


      看到这个异常,很多人会觉得很郁闷,并发修改异常?可我程序并没有运行在多线程的环境当中,而原因是因为,当创建subList时,list会将1个变量modCount传递到subList的构造参数当中,而当list进行修改时,就会对modCount进行累加,而subList在进行操作时,会检查modCount是否和list的一致,若然不一直就抛出异常,这就是原因,这也是subList和数据库视图不同的地方,表修改后直接反应到视图,而list修改后,不会反应到subList,所以在使用subList时,应该使用如下方式对list进行加锁

public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(2);
		List<Integer> subList = list.subList(0, 2);
		// 设置列表为只读状态
		list = Collections.unmodifiableList(list);
		// 再对列表进行操作
		list.add(4);
		
		//运行结果,抛出java.lang.UnsupportedOperationException异常
	}


      使用以上方式就可以明确表示,此列表是只读,当对列表进行操作时,就会抛出异常,增强了语义,而一个List可以有多个subList,但只要存在一个subList,就不能对原List进行操作.请谨记


13.使用Comparator进行排序
      我们都知道,在集合类中要排序时,可以使用JDK提供的帮助工具,例如
Collections中的sort方法对List进行排序,亦可以使用Tree的数据结构来进行排序,例如Set接口中的TreeSet,TreeMap,使用Tree结构来进行排序时,是需要对象拥有比较性的,我们可以在实体类中实现Comparable<T>接口,但排序的方式是多变的,有时经过一段时间后,需求变了,需要按另外一个元素进行排序,但修改了已经稳定的实体类是不应该的,我们可以使用Comparator来进行排序,请看以下代码

public static void main(String[] args) {

		// 使用匿名内部类方式实现
		List<Integer> list = new ArrayList<Integer>();
		Collections.sort(list, new Comparator<Integer>() {

			@Override
			public int compare(Integer o1, Integer o2) {
				// TODO Auto-generated method stub
				return 0;
			}
		});

		// TreeMap实现
		Map<String, Integer> treeMap = new TreeMap<String, Integer>(
				new Comparator<String>() {
					@Override
					public int compare(String o1, String o2) {
						return 0;
					}
				});
	}


      无论是Collections的sort方法和TreeMap,TreeSet都会有重载的方式,接受一个Comparator(比较器),此时有可以在这里进行元素比较的定义


14.使用binarySearch需要注意
      binarySearch(二分查找)是性能较高的一种查找方式,通常我们使用的indexOf为顺序查找,当查找到匹配的值时马上返回,但若然此集合的元素数量多的话,使用顺序查找就性能就会降低,特别是当要查找的元素位于集合的末尾时,效率更低,而二分查找是将数据折半然后进行查找,没有找到指定元素时再折半,但需要注意,二分查找必须保持集合的有序性,所以在开发当中,若要使用二分查找,需先将集合进行排序.这点务必注意


15.集合中元素equlas和compareTo必须同步
      在刚才提及的binarySearch和indexOf两种查找当中,有一点是非常不同的,indexOf的查找的时候是使用equlas来进行匹配,equlas返回为true时认为找到元素,而binarySearch是使用compareTo进行匹配,当compareTo返回0时认为找到元素,而当一个用户实体当中,equlas是使用用户名来重写equlas判断,而compareTo使用密码来比较,那将会导致不必要的错误


16.集合运算时,使用更优雅的方式
      在集合的操作当中,经常会出现两个集合的 并集(or),交集(and),差集(not)等的操作,当然我们可以遍历两个集合,对比元素求出我们需要的并集交集差集等运算的结果,但这种方式处理,真的是最方便?最简单?最优雅?请看以下代码

public static void main(String[] args) {
		List<Integer> list1 = new ArrayList<Integer>();
		List<Integer> list2 = new ArrayList<Integer>();

		// 并集操作
		list1.addAll(list2);

		// 交集操作,retainAll会删除list1中没有出现在list2中的元素
		list1.retainAll(list2);

		// 差集操作
		list1.removeAll(list2);

		// 无重复并集
		list2.removeAll(list1);
		list1.addAll(list2);
	}


17.使用shuffle打乱列表
      现在我们有一个需求,做一个扑克游戏,54张扑克存储到一个集合当中,每次发牌之前,都需要打乱一下扑克的顺序,这样的需求,我们可以有多种实现方式,使用Random来随机调整集合位置,或者集合的位置顺序交换,可有更优雅的方式吗?

public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>();
		// 你好,我是one-line君
		Collections.shuffle(list);
	}


18.多线程时使用Vetor或HashTable
      通过查看JDK API可以发现,Vetor和HashTable是JDK1.0时已存在的类,他们是线程安全的,可在多线程的环境下使用


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

相关推荐

    详解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初级课堂代码

    2. **类与对象**:Java的核心是面向对象编程,因此了解如何定义类,创建对象,以及使用类的成员(属性和方法)至关重要。初学者需要学会封装、继承和多态这三个面向对象的基本特性。 3. **彩票程序代码**:彩票程序...

    Java集合框架总结

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

    corejava12示例代码

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

    达内java学习源代码

    "达内java学习源代码"很可能是达内教育机构提供的Java教学课程中的实践项目或示例代码集合,旨在帮助学员深入理解Java编程概念并提升实际编程技能。 达内的Java培训通常涵盖以下几个关键知识点: 1. **Java基础**...

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

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

    Java集合框架使用总结

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

    Java集合框架培训资料

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

    第13讲 JAVA集合类.ppt

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

    java编程教程代码学习

    从给定的文件信息中,我们可以提取到关于Java编程、BBCode使用以及一些与网络论坛相关的标记语言的知识点。下面将详细阐述这些知识点。 ### Java编程教程代码学习 #### Java编程简介 Java是一种广泛使用的高级...

Global site tag (gtag.js) - Google Analytics