`
able0001
  • 浏览: 28135 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
最近访客 更多访客>>
社区版块
存档分类
最新评论

[转]Java集合的五点体会

    博客分类:
  • Java
阅读更多

 

The Collections classes in java.util were designed to help, namely by replacing arrays and, thus, improving Java performance. As you learned in the previous article, they're also malleable, willing to be customized and extended in all kinds of ways, in service of good, clean code.

Collections are also powerful, however, and mutable: use them with care and abuse them at your own risk.

1. Lists aren't the same as arrays List不同于数组,比如删除这个操作。

Java developers frequently make the mistake of assuming thatArrayList is simply a replacement for the Java array. Collections are backed by arrays, which leads to good performance when looking up items randomly within a collection. And, like arrays, collections use integer-ordinals to obtain particular items. Still, a collection isn't a drop-in replacement for an array.

The trick to differentiating collections from arrays is knowing the difference between order and position. For example, List is an interface that preserves the order in which items are placed into a collection, as Listing 1 shows:


Listing 1. Mutable keys

import java.util.*;

 

public class OrderAndPosition

{

    public static <T> void dumpArray(T[] array)

    {

        System.out.println("=============");

        for (int i=0; i<array.length; i++)

            System.out.println("Position " + i + ": " + array[i]);

    }

    public static <T> void dumpList(List<T> list)

    {

        System.out.println("=============");

        for (int i=0; i<list.size(); i++)

            System.out.println("Ordinal " + i + ": " + list.get(i));

    }

   

    public static void main(String[] args)

    {

        List<String> argList = new ArrayList<String>(Arrays.asList(args));

 

        dumpArray(args);

        args[1] = null;

        dumpArray(args);

       

        dumpList(argList);

        argList.remove(1);

        dumpList(argList);

    }

}

 

When the third element is removed from the above List, the other items "behind" it slide up to fill the empty slots. Clearly, this collections behavior differs from that of an array. (In fact, removing an item from an array is itself not quite the same thing as removing it from a List — "removing" an item from an array means overwriting its index slot with a new reference or null.)

 

2. Iterator, you surprise me!

 

ListIterator,允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。ListIterator 没有当前元素;它的光标位置 始终位于调用 previous()所返回的元素和调用 next() 所返回的元素之间。在长度为 n 的列表中,有 n+1 个有效的索引值,从 0  n(包含)。

 

There's no doubt that Java developers love the Java Collections Iterator, but when was the last time you really looked at theIterator interface? Most of the time, we just slap Iterator inside a for() loop or enhanced for() loop and move on, so to speak.

But, for those who go digging, Iterator has two surprises in store.

First, Iterator supports the ability to remove an object from a source collection safely, by calling remove() on the Iteratoritself. The point here is to avoid a ConcurrentModifiedException, which signals precisely what its name implies: that a collection was modified while an Iterator was open against it. Some collections will let you get away with removing or adding elements to a Collection while iterating across it, but calling remove() on the Iterator is a safer practice.

Second, Iterator supports a derived (and arguably more powerful) cousin. ListIterator, only available from Lists, supports both adding and removing from a List during iteration, as well as bidirectional scrolling through Lists.

Bidirectional scrolling can be particularly powerful for scenarios such as the ubiquitous "sliding set of results," showing 10 of many results retrieved from a database or other collection. It can also be used to "walk backwards" through a collection or list, rather than trying to do everything from the front. Dropping in a ListIterator is much easier than using downward-counting integer parameters to List.get() to "walk backwards" through a List.

 

3. Not all Iterables come from collections读文件内容的实用类

Ruby and Groovy developers like to brag about how they can iterate across a text file and print its contents to the console with a single line of code. Most of the time, they say, doing the same thing in Java programming takes dozens of lines of code: open aFileReader, then a BufferedReader, then create a while() loop to call getLine() until it comes back null. And, of course, you have to do all this in a try/catch/finally block that will handle exceptions and close the file handle when finished.

It may seem like a silly and pedantic argument, but it does have some merit.

What they (and quite a few Java developers) don't know is that not all Iterables have to come from collections. Instead, anIterable can create an Iterator that knows how to manufacture the next element out of thin air, rather than blindly handing it back from a pre-existing Collection:


Listing 2. Iterating a file

// FileUtils.java

import java.io.*;

import java.util.*;

 

public class FileUtils

{

    public static Iterable<String> readlines(String filename)

       throws IOException

    {

       final FileReader fr = new FileReader(filename);

       final BufferedReader br = new BufferedReader(fr);

      

       return new Iterable<String>() {

             public <code>Iterator</code><String> iterator() {

                   return new <code>Iterator</code><String>() {

                         public boolean hasNext() {

                               return line != null;

                         }

                         public String next() {

                               String retval = line;

                               line = getLine();

                               return retval;

                         }

                         public void remove() {

                               throw new UnsupportedOperationException();

                         }

                         String getLine() {

                               String line = null;

                               try {

                                     line = br.readLine();

                               }

                               catch (IOException ioEx) {

                                     line = null;

                               }

                               return line;

                         }

                         String line = getLine();

                   };

             }    

       };

    }

}

 

//DumpApp.java

import java.util.*;

 

public class DumpApp

{

    public static void main(String[] args)

        throws Exception

    {

        for (String line : FileUtils.readlines(args[0]))

            System.out.println(line);

    }

}

 

This approach has the advantage of not holding the entire contents of a file in memory, but with the caveat that, as written, it doesn't close() the underlying file handle. (You could fix this by closing whenever readLine() returns null, but that won't solve cases where Iterator doesn't run to completion.)

 

4. Beware the mutable hashCode() 不要改hashmap的key值

Map is a wonderful collection, bringing us the niftiness of key/value pair collections often found in other languages like Perl. And the JDK gives us a great Map implementation in the form of the HashMap, which uses hashtables internally to support fast key lookups for corresponding values. But therein lies a subtle problem: Keys that support hash codes dependent on the contents of mutable fields are vulnerable to a bug that will drive even the most patient Java developer batty.

Assuming the Person object in Listing 3 has a typical hashCode() (which uses the firstNamelastName, and age fields — all non-final — to calculate the hashCode()), the get() call to Map will fail and return null:


Listing 3. Mutable hashCode() drives me buggy

// Person.java

import java.util.*;

 

public class Person

    implements Iterable<Person>

{

    public Person(String fn, String ln, int a, Person... kids)

    {

        this.firstName = fn; this.lastName = ln; this.age = a;

        for (Person kid : kids)

            children.add(kid);

    }

   

    // ...

   

    public void setFirstName(String value) { this.firstName = value; }

    public void setLastName(String value) { this.lastName = value; }

    public void setAge(int value) { this.age = value; }

   

    public int hashCode() {

        return firstName.hashCode() & lastName.hashCode() & age;

    }

 

    // ...

 

    private String firstName;

    private String lastName;

    private int age;

    private List<Person> children = new ArrayList<Person>();

}

 

 

// MissingHash.java

import java.util.*;

 

public class MissingHash

{

    public static void main(String[] args)

    {

        Person p1 = new Person("Ted", "Neward", 39);

        Person p2 = new Person("Charlotte", "Neward", 38);

        System.out.println(p1.hashCode());

       

        Map<Person, Person> map = new HashMap<Person, Person>();

        map.put(p1, p2);

       

        p1.setLastName("Finkelstein");

        System.out.println(p1.hashCode());

       

        System.out.println(map.get(p1));

    }

}

 

Clearly, this approach is a pain but the solution is easy: Never use a mutable object type as a key in a HashMap.

 

5. equals() vs Comparable

When cruising through the Javadocs, Java developers frequently happen across the SortedSet type (and its lone implementation in the JDK, the TreeSet). Because SortedSet is the only Collection in the java.util package that offers any sorting behavior, developers often begin using it without questioning the details too closely. Listing 4 demonstrates:


Listing 4. SortedSet, I'm so glad I found you!

 

import java.util.*;

 

public class UsingSortedSet

{

    public static void main(String[] args)

    {

        List<Person> persons = Arrays.asList(

            new Person("Ted", "Neward", 39),

            new Person("Ron", "Reynolds", 39),

            new Person("Charlotte", "Neward", 38),

            new Person("Matthew", "McCullough", 18)

        );

        SortedSet ss = new TreeSet(new Comparator<Person>() {

            public int compare(Person lhs, Person rhs) {

                return lhs.getLastName().compareTo(rhs.getLastName());

            }

        });

        ss.addAll(perons);

        System.out.println(ss);

    }

}

 

After working with this code for a while, you might discover one of the Set's core features: that it disallows duplicates. This feature is actually described in the Set Javadoc. A Set is a "collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element."

But this doesn't actually seem to be the case — although none of the Person objects in Listing 4 are equal (according to theequals() implementation on Person), only three objects are present within the TreeSet when printed.

Contrary to the stated nature of the set, the TreeSet, which requires objects to either implement Comparable directly or have aComparator passed in at the time of construction, doesn't use equals() to compare the objects; it uses the compare orcompareTo methods of Comparator/Comparable.

So, objects stored in a Set will have two potential means of determining equality: the expected equals() method and theComparable/Comparator method, depending on the context of who is asking.

What's worse, it isn't sufficient to simply declare that the two should be identical, because comparison for the purpose of sorting isn't the same as comparison for the purpose of equality: It may be perfectly acceptable to consider two Persons equal when sorting by last name, but not equal in terms of their contents.

Always ensure that the difference between equals() and the Comparable.compareTo()-returning-0 is clear when implementing Set. By extension, the difference should also be clear in your documentation.

 

In conclusion

The Java Collections library is scattered with tidbits that can make your life much easier and more productive, if only you know about them. Unearthing tidbits often involves some complexity, however, like discovering that you can have your way withHashMap, just as long as you never use a mutable object type as its key.

So far, we've dug beneath the surface of Collections, but we haven't yet hit the gold mine: Concurrent Collections, introduced in Java 5. The next five tips in this series will focus on java.util.concurrent.

 

From http://www.ibm.com/developerworks/java/library/j-5things3/index.html

分享到:
评论

相关推荐

    java学习心得体会

    在深入学习时,你会遇到Java集合框架,它包括数组列表、链表、队列、栈、映射等数据结构。这些集合工具能帮助你有效地存储和管理数据。特别是HashMap和ArrayList,它们在实际开发中有着广泛的应用。 异常处理是Java...

    使用Java集合模拟JSTL包中的Result接口功能

    如果一切正常,那么可以看到一个使用Java集合框架完成的通过BaseDAO类,而不是使用jstl包完成的。 注意:在BaseDAO类有两个重载的方法:findAllTable方法,第一个是使用jstl包的Result接口对象;第二是本人使用集合...

    java实习总结与体会.pdf

    首先,对于Java实习,通常会涉及到的知识点可能包括Java基础语法、面向对象编程、Java集合框架、异常处理、输入输出流(I/O)以及Java的图形用户界面(GUI)编程等。 1. Java基础语法:在实习过程中,首先需要掌握...

    2022java实验心得体会(精选5篇)_java实验报告心得体会.docx

    "2022java实验心得体会(精选5篇)_java实验报告心得体会.docx" 通过分析文件的标题、描述、标签和部分内容,可以总结出以下几个重要的知识点: 1. Java Web技术:Java Web是使用Java技术来解决相关web互联网领域...

    Java多线程知识点总结

    在Java中,线程的生命周期包含五个基本状态,分别是新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked)和死亡状态(Dead)。了解这些状态对于掌握Java多线程编程至关重要。 新建...

    java体会总集java体会总集

    接着,Java集合框架是处理数据的重要工具。ArrayList、LinkedList、HashSet、HashMap等接口和类提供了灵活的数据存储和操作方式。理解它们的区别和应用场景,能够优化代码性能。 再者,多线程是Java的一大特色。...

    java面试中出现的面试题集合,基础集合,面试宝典.zip

    Java基础知识点:包括数据类型、面向对象特性、异常处理、集合框架等。 Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 ...

    Java学习心得,希望对大家有帮助!

    根据提供的标题、描述以及部分代码内容,我们可以总结出以下与Java...以上就是从标题、描述及部分内容中提炼出来的关于Java学习的心得体会及相关知识点。通过这些内容,希望能为初学者提供一个较为全面的Java学习指南。

    Java编程体会.pdf

    Java编程体会主要涵盖以下几个关键知识点: 1. **内部类**: - **内部类向上转型**:内部类可以被声明为父类或接口的类型,这使得内部类的实例可以被当作其父类或接口的实例来使用,隐藏其实现细节。 - **局部...

    2022年java学习心得体会_JAVA实训的心得.docx

    从“2022年java学习心得体会”文档中可以看出,作者通过自己的学习经历,分享了关于Java学习的一些关键点和经验。 首先,Java的学习需要扎实的基础。作者提到,初次接触Java时,对main方法的定义感到困惑,但通过...

    Java课堂笔记、代码、java核心知识点梳理、java笔试面试资料.zip

    Java基础知识点:包括数据类型、面向对象特性、异常处理、集合框架等。 Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 ...

    java 心得体会 基础总结

    - **J2SE(Java Platform, Standard Edition)**: 是Java的基础版本,提供了一套标准的API集合,适用于桌面应用程序和一些基本的应用开发。 - **J2ME(Java Platform, Micro Edition)**: 针对移动设备和嵌入式系统...

    JAVA做完项目心得

    3. **集合框架**:Java集合框架是项目中不可或缺的部分,我学会了ArrayList、LinkedList、HashSet、HashMap等各种数据结构的使用,理解了它们的性能特性和适用场景。 4. **IO流**:在处理文件输入输出时,我学习了...

    Java Collections 作者 APress

    Java集合框架被分为两大类:Collection接口,主要处理一组单一元素,以及Map接口,处理键值对。 2. Collection接口及其子接口:Collection接口是所有单列集合的根接口,其子接口包括List、Set和Queue。List接口代表...

    java的心得体会.pdf

    【Java学习心得体会】 Java作为一款面向对象的编程语言,其学习过程充满了探索与实践。学习Java,首先要认识到兴趣是入门的最好导师。在接触Java的第一步,编写经典的"Hello World"程序,虽然简单,但却是开启Java...

    Java的实训心得体会范文.doc

    Java实训心得体会 Java作为一种广泛应用的编程语言,其实训过程对于理解和掌握这门技术至关重要。通过实际操作,将理论知识转化为代码实现,是成为一名合格的Java程序员的必经之路。以下是对Java实训的一些主要心得...

    使用JavaScript数组模拟Java的Hashtable集合

    在讲授JavaSript课程第七章时,发现课件中没有把JavaScript的数组讲清楚。因为,JavaScript的数组非常特殊,...注:本示例代码注释非常详细,请仔细阅读体会JavaScript数组的奇特用法,以及对象的构造方法的书写格式。

    java编程思想_java_

    不可将Java简单想象成一系列特性的集合;如孤立地看,有些特性是没有任何意义的。只有在考虑“设计”、而非考虑简单的编码时,才可真正体会到Java的强大。为了按这种方式理解Java,首先必须掌握它与编程的一些基本...

    2022年java实训心得体会范文.docx

    【Java实训心得体会】 Java实训是计算机科学特别是软件工程专业学生必不可少的一部分,它是理论知识与实践操作相结合的关键步骤。通过2022年的Java实训,学生深入理解了Java编程语言的核心概念,增强了动手能力和...

    java学习心得

    从给定的文件信息中,我们可以提炼出一系列与Java学习及面向对象编程(Object-Oriented Programming,简称OOP)相关的关键知识点。以下是对这些知识点的详细解析: ### 面向对象编程概述 面向对象编程是一种被广泛...

Global site tag (gtag.js) - Google Analytics