Java编程手冊-Collection框架(上)

该文章所讲内容基本涵盖了Collection里面的全部东西,尽管基于jdk 1.5的。可是思路非常清晰

1.引言

1.1 Collection框架的介绍

尽管我们能够使用数组去存储具有同样类型的元素集合(包含基本类型和对象类型),可是数组不支持所谓的动态内存分配,一旦分配之后,它的长度就是固定的,无法改变,另外,数组是一个简单的线性结构。在我们的实际开发中,可能会须要更复杂的数据结构。比如linked list, stack, hash table, sets, 或者 trees.

在Java中,有统一的Collection框架来支持这样的动态分配的数据结构(比如:ArrayList, LinkedList, Vector, Stack, HashSet, HashMap, Hashtable),它通过接口统一了全部继承类的基本操作,形成了一套主要的体系。

Java集合框架包(java.util)里包括以下内容:

1、接口集合

2、类实现

3、算法(比如排序和查找)

1.2 Colloction样例— ArrayList (Pre-JDK 1.5)

ArrayList是一个线性的数据结构,类似于数组。可是它是可伸缩的。

以下使用了ArrayList来存放String集合对象。

// Pre-JDK 1.5
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

public class ArrayListPreJDK15Test {
   public static void main(String[] args) {
      List lst = new ArrayList();  // A List contains instances of Object. Upcast ArrayList to List
      lst.add("alpha");            // add() takes Object. String upcast to Object implicitly
      lst.add("beta");
      lst.add("charlie");
      System.out.println(lst);     // [alpha, beta, charlie]

      // Get a "iterator" instance from List to iterate thru all the elements of the List
      Iterator iter = lst.iterator();
      while (iter.hasNext()) {      // any more element
         // Retrieve the next element, explicitly downcast from Object back to String
         String str = (String)iter.next();
         System.out.println(str);
      }
   }
}

程序分析

  • 2-4行引入了java.util包中集合框架的类和接口

上图能够看到ArrayList的继承关系。我们能够看到ArrayList实现了List, Collection 和 Iterable接口。Collection和Iterable接口定义了全部集合都须要实现的基本操作。Collection接口定义了怎样加入和移除一个元素。Iterable接口定义了一种机制去遍历集合中的全部元素。

一般不直接使用Collection接口,而是使用它的子接口List(支持索引訪问的有序列表)、Set(不同意元素的反复)、Queue(先进先出)。

  • 在第8行中。创建了一个ArrayList实例。并将它向上转换为List接口,由于ArrayList实现了List接口,一般比較良好的编程操作都是在接口上面,而不是在它的实现上面。Collection框架提供了一个接口集合,这样你能够使用这些接口而不是它的实现。

  • Collection接口定义了一些对主要的操作方法。

// Pre-JDK 1.5
boolean add(Object element)     // adds an element
boolean remove(Object element)  // removes an element
int size()                      // returns the size
boolean isEmpty()               // checks if empty</span>

能够看到。在pre-JDK
1.5上,add(Object)方法操作的是Object对象,Object类是全部类的超类,因此,全部类都是Object类的子类,不论什么Java类都能够向上转换为Object类。然后加入到集合中,而且这个转换是编译器隐式操作的。它是类型安全的。

  • Iterable接口包括一个抽象方法去获取集合所关联的Iterator对象,这样通过Iterator对象就能够遍历整个集合。
Iterator iterator();   // returns an Iterator object to iterate thru all the elements of the collection
  • Iterator声明了以下的抽象方法进行集合遍历
// Pre-JDK 1.5
boolean hasNext()  // returns true if it has more elements
Object next()      // returns the next element
void remove()      // removes the last element returned by the iterator</span>
  • 第15-20行获取ArrayList相关联的Iterator对象,而且使用while循环来遍历集合。
  • 在18行,iter.next() 方法方法返回的是Object类型的对象。这个在上面add(Object)中说过,我们在得到Object类型的对象之后,须要显式的将类型转换为String类型,由于编译器不知道我们须要的详细类型。

  • 事实上我们也能够使用LinkedList, Vector 和 Stack。而且仅仅须要改动第8行的实例化代码就可以,其它不变,这也能够看出接口的统一性。尽管实现不同,可是操作的效果同样。
List lst = new LinkedList();   // use "LinkedList" implementation
// or
List lst = new Vector();       // use "Vector" implementation
// or
List lst = new Stack();        // use "Stack" implementation

1.3  Pre-JDK 1.5 Collections不是类型安全的

Pre-JDK 1.5存在以下的缺陷:

1、编译器会将元素隐式地向上转换为java.lang.Object,可是当我们获取元素的时候,我们获取的就是java.lang.Object类型的对象,我们须要显式的将它向下转换为我们的原始类型。

2、编译器不能在编译时检查向下转换的有效性。错误的向下转换会在执行是抛出ClassCastException异常。

这两个问题事实上在上面代码的分析过程中也说到过,缺陷也非常明显。

// lst is designed to hold Strings
lst.add(new Integer(88));  // adds an Integer, implicitly upcast to Object, okay in compile/runtime

Iterator iter = lst.iterator();
while (iter.hasNext()) {
   String str = (String)iter.next(); // compile okay but runtime ClassCastException
   System.out.println(str);
}

1.4 JDK 1.5中引入泛型

针对上面的缺陷。JDK 1.5中引入了一个新的特性——泛型。它能够传递类型信息,这样编译器在编译的过程中能够进行必要的类型检查。这样就避免的执行是类型安全问题。

List<String> lst = new ArrayList<String>();  // read as List of Strings, ArrayList of Strings

上面我们传递了一个String类型,在ArrayList内部的操作使用的就是String类型,避免了类型的转换。假设加入其它类型的元素,编译器就会报错。

1.5 带有泛型的ArrayList

// Post-JDK 1.5 with Generics
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

public class ArrayListPostJDK15Test {
   public static void main(String[] args) {
      List<String> lst = new ArrayList<String>();  // Inform compiler about the type
      lst.add("alpha");         // compiler checks if argument's type is String
      lst.add("beta");
      lst.add("charlie");
      System.out.println(lst);  // [alpha, beta, charlie]

      Iterator<String> iter = lst.iterator();   // Iterator of Strings
      while (iter.hasNext()) {
         String str = iter.next();  // compiler inserts downcast operator
         System.out.println(str);
      }

//      lst.add(new Integer(1234));   // ERROR: compiler can detect wrong type
//      Integer intObj = lst.get(0);  // ERROR: compiler can detect wrong type

      // Enhanced for-loop (JDK 1.5)
      for (String str : lst) {
         System.out.println(str);
      }
   }
}

能够看到,使用泛型之后。就基本不存在前面所说隐式和显式类型转换了,由于内部使用的就是我们传递进去的类型。而不是上面所说的Object类型,假设加入其它类型的话,编译器就会报错。

1.6 向后兼容

JDK 1.5是兼容pre-JDK 1.5的使用的。比如在JDK 1.5中使用pre-JDK 1.5的使用方法,仍然是能够运行的,仅仅是相同没有类型检查。

// Pre-JDK 1.5
List lst = new ArrayList();  // No type information
lst.add("alpha");   // Without generics, compiler can't check if the type is correct

1.7 自己主动装箱和自己主动拆箱(JDK 1.5)

一个集合仅仅能存放对象,它不能包括基本数据类型,比如int或者double,这就存在问题了。虽然数组能够存放基本数据类型,可是前面说过它是不可扩展的。所以假设希望在集合中存放基本数据类型。就必须使用相应的包装类把基本数据类型包装成相应类型的对象,以下这副图相应的就是基本数据类型与对象类型的相应关系。

在JDK 1.5之前,向集合加入元素。必须将基本数据类型包装为相应的对象类型。从集合获取元素,必须把相应对象类型拆解为相应的基本数据类型。

// Pre-JDK 1.5
Integer intObj = new Integer(5566);    // wrap int to Integer
int i = intObj.intValue();             // unwrap Integer to int

Double doubleObj = new Double(55.66);  // wrap double to Double
double d = doubleObj.doubleValue();    // unwrap Double to double

从上面能够看到。在JDK 1.5之前,装箱和解箱操作须要我们自己手动去完毕。JDK 1.5就针对这一问题。提出了一个新特性。就是自己主动装箱与解箱。也就是本来须要我们手工完毕的事情。编译器帮助我们完毕了。

// JDK 1.5
Integer intObj = 5566;    // autobox from int to Integer
int i = intObj;           // auto-unbox from Integer to int

Double doubleObj = 55.66; // autoboxing from double to Double
double d = doubleObj;     // atuo-unbox from Double to double

样例—Pre JDK 1.5中集合

Pre
JDK 1.5不支持泛型、自己主动装箱与解箱和for-each循环,以下的代码就显得混乱而且不是类型安全的。

// Pre-JDK 1.5
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

public class PrimitiveCollectionPreJDK15 {
   public static void main(String[] args) {
      List lst = new ArrayList();

      // Add 10 random primitive int into the List
      Random random = new Random();
      for (int i = 1; i <= 10; ++i) {
         // Wrap the primitive int into Integer, upcast to Object
         lst.add(new Integer(random.nextInt(10)));
      }
      System.out.println(lst);

      Iterator iter = lst.iterator();
      while (iter.hasNext()) {
         // Explicit downcast to Integer, then unwrap to int
         int i = ((Integer)iter.next()).intValue();   // un-safe at runtime
         System.out.println(i);
      }
   }
}

样例—Post-JDK 1.5中的集合

在JDK1.5之后,就支持了泛型、自己主动装箱与解箱以及for-each循环,代码会更加简洁而且是类型安全的。

// Post-JDK 1.5
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

public class PrimitiveCollectionJDK15 {
   public static void main(String[] args) {
      List<Integer> lst = new ArrayList<Integer>();

      // Add 10 random primitive int into the List
      Random random = new Random();
      for (int i = 1; i <= 10; ++i) {
         lst.add(random.nextInt(10)); // autobox to Integer, upcast to Object, type-safe
      }
      System.out.println(lst);

      // Transverse via iterator
      Iterator<Integer> iter = lst.iterator();
      while (iter.hasNext()) {
         int i = iter.next();  // downcast to Integer, auto-unbox to int, type-safe
         System.out.println(i);
      }

      // Transverse via enhance for-loop
      for (int i : lst) {      // downcast to Integer, auto-unbox to int, type-safe
         System.out.println(i);
      }

      // Retrieve via for-loop with List's index
      for (int i = 0; i < lst.size(); ++i) {
         int j = lst.get(i);   // downcast to Integer, auto-unbox to int, type-safe
         System.out.println(j);
      }
   }
}

2. Collection接口

下图是Collection框架中的接口和经常使用实现类

2.1  Iterable<E>接口

Iterable<E>接口。它包括了一个泛型类型E。E相应的就是集合元素类型,这个接口声明了一个抽象方法iterator() 用来获取一个Iterator<E>对象,Iterator用来遍历它所关联集合的全部元素。

Iterator<E> iterator();   // Returns the associated Iterator instance
                          // that can be used to transverse thru all the elements of the collection

全部Collection的实现(比如:ArrayListLinkedListVector)必须实现这种方法,而且返回的对象也实现了Iterator接口。

2.2
 Iterator<E>接口

Iterator<E>接口声明了以下三个抽象方法。

boolean hasNext()  // Returns true if it has more elements
E next()           // Returns the next element of generic type E
void remove()      // Removes the last element returned by the iterator

我们能够使用Iterator和一个while循环进行集合的遍历

List<String> lst = new ArrayList<String>();
lst.add("alpha");
lst.add("beta");
lst.add("charlie");

// Retrieve the Iterator associated with this List via the iterator() method
Iterator<String> iter = lst.iterator();
// Transverse thru this List via the Iterator
while (iter.hasNext()) {
   // Retrieve each element and process
   String str = iter.next();
   System.out.println(str);
}

2.3 加强版的for循环 (JDK 1.5)

对于使用Iterator进行集合的遍历,在JDK 1.5中引入了新的加强版的for循环,使用它进行集合的遍历更加方便。

以下是主要的使用方法

for ( type item : aCollection ) {
   body ;
}

能够在集合中改动对象吗?

加强版的for循环提供了一个方便的方法去遍历集合元素,可是它将Iterator给隐藏了,因此你不能移除或者替换这个元素。

循环变量接受的是一个引用的副本。因此这个加强版的for循环能够通过该引用改动相应的可变元素(比如:StringBuilder),可是不能改动不可变元素(比如:String和基本数据类型相应的对象类型)。

样例——使用加强版的for循环对于集合的可变元素(比如:StringBuilder)

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

public class ForEachMutableTest {
   public static void main(String[] args) {
      List<StringBuilder> lst = new ArrayList<StringBuilder>();
      lst.add(new StringBuilder("alpha"));
      lst.add(new StringBuilder("beta"));
      lst.add(new StringBuilder("charlie"));
      System.out.println(lst);   // [alpha, beta, charlie]

      for (StringBuilder sb : lst) {
         sb.append("88");   // can modify "mutable" objects
      }
      System.out.println(lst);  // [alpha88, beta88, charlie88]
   }
}

样例——使用加强版的for循环对于集合的不可变元素(比如:StringBuilder)

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

public class ForEachImmutableTest {
   public static void main(String[] args) {
      List<String> lst = new ArrayList<String>();
      lst.add("alpha");
      lst.add("beta");
      lst.add("charlie");
      System.out.println(lst);   // [alpha, beta, charlie]

      for (String str : lst) {
         str += "change!";   // cannot modify "immutable" objects
      }
      System.out.println(lst);   // [alpha, beta, charlie]
   }
}

2.4  Collection<E>接口

Collection<E>包括一个泛型类型E,E是集合的元素数据类型,而且Collection<E>是集合框架的超类。它包括了其它类都须要实现的基本操作,比如:

// Basic Operations
int size()                        // Returns the number of elements of this Collection
void clear()                      // Removes all the elements of this Collection
boolean isEmpty()                 // Returns true if there is no element in this Collection
boolean add(E element)            // Ensures that this Collection contains the given element
boolean remove(Object element)    // Removes the given element, if present
boolean contains(Object element)  // Returns true if this Collection contains the given element

// Bulk Operations with another Collection
boolean containsAll(Collection<?> c)       // Collection of any "unknown" object
boolean addAll(Collection<? extends E> c)  // Collection of E or its sub-types
boolean removeAll(Collection<?> c)
boolean retainAll(Collection<?

> c)

// Comparison - Objects that are equal shall have the same hashCode
boolean equals(Object o)
int hashCode()

// Array Operations
Object[] toArray()       // Convert to an Object array
<T> T[] toArray(T[] a)   // Convert to an array of the given type T

Collection<E>中仅仅能包括对象类型。不能包括基本数据类型(比如:int和double),所以假设须要将基本数据类型包装成相应的对象类型,JDK
1.5引入了自己主动拆箱和解箱操作来解决问题,这个在前面已经讲过。

2.5  List<E>, Set<E> & Queue<E> — Collection<E>的子接口

在实际开发过程中。我们一般使用Collection的子类接口——List<E>Set<E>,
和 Queue<E>。它们提供了很多其它其它的特性。

  • List<E>:它相当于一个可扩展的线性数组,能够进行索引訪问,而且能够包括反复的元素,我们常常会使用到的一些List的实现类为: ArrayListLinkedListVector 和 Stack。
  • Set<E>:相当于一个数据集合,它不能包括反复的元素。常常使用到的Set的实现类为:HashSet和 LinkedHashSet,子接口为SortedSet<E> 是一个有序的元素集合,TreeSet是SortedSet<E> 的实现类。

  • Queue<E>:
    相当于一个先进先出的队列,它的子接口Deque<E>相当于一个可在两端操作的双向队列,实现类为PriorityQueueArrayDeque 和 LinkedList。

2.6  Map<K,V>接口

接口Map<K,V>包括了两个泛型类型K和V。它们组成一个键值对。Map就是一个键值对的集合,键值key是不同意反复的,常常使用到的实现类为HashMapHashtable 和 LinkedHashMap。它的子接口 SortedMap<K,
V>
 表示一个基于键值key有序的键值对集合,实现类为TreeMap。

须要注意的是,Map<K,V>不是Collection<E>的子接口。

3. List<E>接口与实现

在实际的编程中。我们很多其它使用的是Collection的子接口ListSet,
和 Queue来取代Collection接口,这些子接口仅仅是对Collection接口操作的又一次定义。

 
  List<E>相当于一个可扩展的线性数组,它支持索引訪问,它能够包括反复的元素,也能够包括null元素。

List<E> 父接口的基础上,List<E> 也声明了一些抽象方法。

// Operations at a specified index position
void add(int index, E element)    // add
E set(int index, E element)       // replace
E get(int index)                  // retrieve without remove
E remove(int index)               // remove last retrieved
int indexOf(Object obj)
int lastIndexOf(Object obj)
// Operations on a range fromIndex (inclusive) toIndex (exclusive)
List<E> subList(int fromIndex, int toIndex)
......

// Operations inherited from Collection<E>
int size()
boolean isEmpty()
boolean add(E element)
boolean remove(Object obj)
boolean contains(Object obj)
void clear();
......

抽象类AbstractList提供了非常多List、Collector和Iterable接口中声明的抽象方法的实现。另外有些方法仍然是抽象的。这些方法会被子类实现,比如ArrayList 和 Vector。

3.1
 ArrayList<E> & Vector<E> —— List<E>的实现类

ArrayList<E>是List接口全面的实现类,非常多实用的方法已经被AbstractList实现。可是ArrayList也进行了重写。ArrayList不是线程同步的,因此它不是线程安全的。

Vector是JDK 1.0中遗留的类。在JDK
1.2中将它更新到了Collection中。它是List接口的一个线程同步(线程安全)的实现。包括了非常多遗留的方法(比如:addElement()removeElement()setElement()elementAt()firstElement()lastElement()insertElementAt()),毫无疑问,这些遗留的方法是能够使用的。而且保持向后兼容。

须要注意的是,尽管ArrayList<E>不是线程安全的,而Vector是线程安全的,可是ArrayList<E>显然比Vector有更好的性能。

3.2
 Stack<E>——List<E>的实现类

Stack<E>是一个后进先出的队列,它扩展于Vector。它是一个同步的可扩展的数组,也就是它是线程安全的,包括了以下方法。

E push(E element)       // pushes the specified element onto the top of the stack
E pop()                 // removes and returns the element at the top of the stack
E peek()                // returns the element at the top of stack without removing
boolean empty()         // tests if this stack is empty
int search(Object obj)  // returns the distance of the specified object from the top
                        //  of stack (distance of 1 for TOS), or -1 if not found

3.3  LinkedList<E> - List<E>的实现类

LinkedList<E>是一个双向链表,它实现了List<E>接口,在元素的插入和删除上,效率更高,可是浪费了很多其它复杂的结构。

 
  LinkedList<E>
 也实现了Queue<E> 和 Deque<E>,因此它能够充当FIFO
和 LIFO队列。

3.4
转换一个List为一个数组 - toArray()

在超类接口Collection中定义了一个toArray()方法,它能够使用该列表来创建一个数组。返回的数组能够进行自由的改动。

Object[] toArray()      // Object[] version
<T> T[] toArray(T[] a)  // Generic type version

样例:

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
public class TestToArray {
   public static void main(String[] args) {
      List<String> lst = new ArrayList<String>();
      lst.add("alpha");
      lst.add("beta");
      lst.add("charlie");

      // Use the Object[] version
      Object[] strArray1 = lst.toArray();
      System.out.println(Arrays.toString(strArray1));   // [alpha, beta, charlie]

      // Use the generic type verion - Need to specify the type in the argument
      String[] strArray2 = lst.toArray(new String[0]);
      strArray2[0] = "delta";   // modify the returned array
      System.out.println(Arrays.toString(strArray2));   // [delta, beta, charlie]
      System.out.println(lst);  // [alpha, beta, charlie] - no change in the original list
   }
}

3.5 将数组转换为一个List - Arrays.asList()

工具类java.util.Arrays提供了静态方法Arrays.asList()能够将数组转换为List<T>,可是,假设改动了List里面的元素内容。数组中对应的元素内容也会改变,反之亦然。

样例:

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
public class TestArrayAsList {
   public static void main(String[] args) {
      String[] strs = {"alpha", "beta", "charlie"};
      System.out.println(Arrays.toString(strs));   // [alpha, beta, charlie]

      List<String> lst = Arrays.asList(strs);
      System.out.println(lst);  // [alpha, beta, charlie]

      // Changes in array or list write thru
      strs[0] += "88";
      lst.set(2, lst.get(2) + "99");
      System.out.println(Arrays.toString(strs)); // [alpha88, beta, charlie99]
      System.out.println(lst);  // [alpha88, beta, charlie99]

      // Initialize a list using an array
      List<Integer> lstInt = Arrays.asList(22, 44, 11, 33);
      System.out.println(lstInt);  // [22, 44, 11, 33]
   }
}

3.6 ArrayList, Vector, LinkedList 和 Stack的比較

4.
排序与查找

  • 使用Collections.sort() 和 Arrays.sort()可进行排序
  • 有些集合,比如SortedSet (TreeSet)
    和 SortMap (TreeMap)是有序的

有两种方法进行排序:

  • 是对象实现java.lang.Comparable,重写compareTo()方法去指定两个对象的排序方法。
  • 创建一个指定的java.util.Comparator对象。实现compare()方法去指定两个对象的比較。

4.1  java.lang.Comparable<T>接口

java.lang.Comparable<T>能够指定两个对象怎样进行比較,它定义了一个抽象方法。

int compareTo(T o)  // Returns a negative integer, zero, or a positive integer
                    // as this object is less than, equal to, or greater than the given object

一般推荐compareTo()方法与equals() 和 hashCode()是一致的,即:

  • 假设compareTo()返回0。那么equals()应该返回true。
  • 假设equals()返回true,那么hashCode()应该返回的是同样的int值。

全部基本数据类型的包装类(比如:ByteShortIntegerLongFloatDoubleCharacter and Boolean)都实现了Comparable接口的compareTo() 方法。

样例:

工具类 java.util.Arrays 和 java.util.Collections相应不同的算法提供了非常多的静态方法,比如排序和查找。

在以下这个样例中,使用Arrays.sort() 和 Collections.sort() 方法去对一个String数组和一个Integer的List进行排序,使用的就是它们默认的Comparable实现。

import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

public class TestComparable {
   public static void main(String[] args) {
      // Sort and search an "array" of Strings
      String[] array = {"Hello", "hello", "Hi", "HI"};

      // Use the Comparable defined in the String class
      Arrays.sort(array);
      System.out.println(Arrays.toString(array));  // [HI, Hello, Hi, hello]

      // Try binary search - the array must be sorted
      System.out.println(Arrays.binarySearch(array, "Hello")); // 1
      System.out.println(Arrays.binarySearch(array, "HELLO")); // -1 (insertion at index 0)

      // Sort and search a "List" of Integers
      List<Integer> lst = new ArrayList<Integer>();
      lst.add(22);  // auto-box
      lst.add(11);
      lst.add(44);
      lst.add(33);
      Collections.sort(lst);    // Use the Comparable of Integer class
      System.out.println(lst);  // [11, 22, 33, 44]
      System.out.println(Collections.binarySearch(lst, 22)); // 1
      System.out.println(Collections.binarySearch(lst, 35)); // -4 (insertion at index 3)
   }
}

4.2  java.util.Comparator<T> 接口

在Comparable之外,我们能够传递一个Comparator对象到排序方法中(Collections.sort() 和 Arrays.sort())来实现大小比較,假设Comparator可用,那么Comparator将会重写Comparable。

int compare(T o1, T o2)    // Returns a negative integer, zero, or a positive integer as the
                           // first argument is less than, equal to, or greater than the second.

须要注意的是,你须要创建Comparator<T>实例。而且实现compare() 方法去进行对象的比較。在Comparable中,仅仅须要调用对象的compareTo()方法。它仅仅须要传递一个參数,表示当前对象和还有一个对象比較,在Comparator<T>须要传递两个參数。表示两个对象的比較。

样例

import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class TestComparator {

   // Define a Comparator<String> to order strings in case-insensitive manner
   public static class StringComparator implements Comparator<String> {
      @Override
      public int compare(String s1, String s2) {
         return s1.compareToIgnoreCase(s2);
      }
   }

   // Define a Comparator<Integer> to order Integers based on the least significant digit
   public static class IntegerComparator implements Comparator<Integer> {
      @Override
      public int compare(Integer s1, Integer s2) {
         return s1%10 - s2%10;
      }
   }

   public static void main(String[] args) {
      // Use a customized Comparator for Strings
      Comparator<String> compStr = new StringComparator();

      // Sort and search an "array" of Strings
      String[] array = {"Hello", "Hi", "HI", "hello"};
      Arrays.sort(array, compStr);
      System.out.println(Arrays.toString(array));  // [Hello, hello, Hi, HI]
      System.out.println(Arrays.binarySearch(array, "Hello", compStr)); // 1
      System.out.println(Arrays.binarySearch(array, "HELLO", compStr)); // 1 (case-insensitive)

      // Use a customized Comparator for Integers
      Comparator<Integer> compInt = new IntegerComparator();

      // Sort and search a "List" of Integers
      List<Integer> lst = new ArrayList<Integer>();
      lst.add(42);  // auto-box
      lst.add(21);
      lst.add(34);
      lst.add(13);
      Collections.sort(lst, compInt);
      System.out.println(lst);  // [21, 42, 13, 34]
      System.out.println(Collections.binarySearch(lst, 22, compInt)); // 1
      System.out.println(Collections.binarySearch(lst, 35, compInt)); // -5 (insertion at index 4)
   }
}

建议接着看Java编程手冊-Collection框架(下)

參考文章:Java
Programming Tutorial The Collection Framework

时间: 2024-10-13 05:10:18

Java编程手冊-Collection框架(上)的相关文章

阿里Java开发手冊之编程规约

对于程序猿来说,编程规范能够养成良好的编程习惯,提高代码质量,减少沟通成本.就在2月9号,阿里出了一份Java开发手冊(正式版),分为编程规约.异常日志.MySQL规约,project规约.安全规约五个章节. 这里我依据阿里的编程规约,重点记录(黑色加粗部分)自己还未做好的一些规范,同一时候方便查阅. 编程规约 一.命名规约 [强制]代码中的命名均不能下面划线或美元符号開始.也不能下面划线或美元符号结束. 反例: _name / __name / $Object / name_ / name$

Java编程的逻辑 (24) - 异常 (上)

之前我们介绍的基本类型.类.接口.枚举都是在表示和操作数据,操作的过程中可能有很多出错的情况,出错的原因可能是多方面的,有的是不可控的内部原因,比如内存不够了.磁盘满了,有的是不可控的外部原因,比如网络连接有问题,更多的可能是程序的编程错误,比如引用变量未初始化就直接调用实例方法. 这些非正常情况在Java中统一被认为是异常,Java使用异常机制来统一处理,由于内容较多,我们分为两节来介绍,本节介绍异常的初步概念,以及异常类本身,下节主要介绍异常的处理. 我们先来通过一些例子认识一下异常. 初始

Java编程的逻辑 (35) - 泛型 (上) - 基本概念和原理

之前章节中我们多次提到过泛型这个概念,从本节开始,我们就来详细讨论Java中的泛型,虽然泛型的基本思维和概念是比较简单的,但它有一些非常令人费解的语法.细节.以及局限性,内容比较多. 所以我们分为三节,逐步来讨论,本节我们主要来介绍泛型的基本概念和原理,下节我们重点讨论令人费解的通配符,最后一节,我们讨论一些细节和泛型的局限性. 后续章节我们会介绍各种容器类,容器类可以说是日常程序开发中天天用到的,没有容器类,难以想象能开发什么真正有用的程序.而容器类是基于泛型的,不理解泛型,我们就难以深刻理解

【JAVA】几个collection框架

Arrays public static void main(String[] args) { //binarySearch,注意二分查找要求数组有序 int[] nums1 = {2,4,6,8,10}; Arrays.binarySearch(nums1, 1);//返回-1 Arrays.binarySearch(nums1, 8);//返回3 //copyOf,截取or用0填充,该拷贝不影响原来的数组 int[] nums2 = Arrays.copyOf(nums1, 3); //co

Java编程手册-Collection框架(下)

5.  Set<E>接口与实现 Set<E>接口表示一个数学的集合,它不允许元素的重复,只能包含一个null元素. Set<E>接口声明了下面抽象方法. boolean add(E o) // add the specified element if it is not already present boolean remove(Object o) // remove the specified element if it is present boolean con

java书籍推荐:《Java SE 6 技術手冊》

Java SE 6 技術手冊 或  Java SE 6 技術手冊 Java SE 6 技術手冊 為什麼選擇用 Markdown?只是單純把文件重新排版太無聊了,不如趁這個機會學些新東西,所以我就藉這個機會來學著用 Markdown,並看看它有什麼好處與壞處 ... 如果你需要 PDF 與 epub 格式,而又有點懶自己轉換,那麼可以考慮在 Google Play 或 Pubu 上向便當價致敬,如果你需要 mobi 格式,可以使用 calibre 把 epub 轉為 mobi ... :) 我在

[笔记][Java7并发编程实战手冊]3.8 并发任务间的数据交换Exchanger

[笔记][Java7并发编程实战手冊]系列文件夹 简单介绍 Exchanger 是一个同步辅助类.用于两个并发线程之间在一个同步点进行数据交换. 同意两个线程在某一个点进行数据交换. 本章exchanger 使用心得总结 两个线程必须使用同一个Exchanger对象,且仅仅能是两个线程间的数据交换 exchanger.exchange(v)的时候,当前线程会被堵塞,直到还有一个线程运行该方法,同一时候完成数据的交换 相似这样的数据交换的,生产者线程一定要先生产数据.再交换数据,消费者线程一定要先

java中Collection框架的讲解

下面要开始java中相关集合框架的学习啦. Are you ready?Let's go~~ 今天要讲解的Java中的Collection框架. 1) 首先查看jdk中Collection类的源码后会发现如下内容: ... * @see AbstractCollection * @since 1.2 */ public interface Collection<E> extends Iterable<E> { // Query Operations 通过查看可以发现Collecti

C# 6 与 .NET Core 1.0 高级编程 - 38 章 实体框架核心(上)

译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 38 章 实体框架核心(上)),不对的地方欢迎指出与交流. 章节出自<Professional C# 6 and .NET Core 1.0>.水平有限,各位阅读时仔细分辨,唯望莫误人子弟. 附英文版原文:Professional C# 6 and .NET Core 1.0 - 38 Entity Framework Core ------------------------------- 本章内容 En