Java集合基础

来源:互联网 发布:启动gta5需要网络连接 编辑:程序博客网 时间:2024/06/05 00:18

真是好久没来写东西了,看的东西学的东西也不少,但是说没时间也不至于,虽然最近996,只是自己懒癌犯了罢。前天学东西睡觉前突然又跳出个想法:技术学得再好又能怎么样呢,只要没达到顶峰,貌似在目前的情况下会的东西再多再好,都没有什么用,理解业务,安排计划完成基础编码就行了,想多了反而会出问题,导致开发变慢,呵呵了。但我还是不能放弃啊……


这两天把集合框架系统的看了一遍,也是简单的看看,以前一直都没有系统学过集合框架,只是在用HashMap和ArrayList,偶尔使用HashSet,这两天终于下定决心好好学学了,虽然每天也是要搞到一两点。看完还是觉得挺好的。两天时间把笔记简单的整理了下,说是整理,其实就是把书上的内容敲到电脑上罢了。在这里粘贴一份吧。


笔记:


为了保存数量不确定的数据,以及保存具有映射关系的数据(也被称为关联数组)。Java提供集合类,集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类。所有集合类都位于java.util包下。后来为了处理多线程情况下的并发安全问题,java5在java.util.concurrent包下提供了一些多线程支持的集合类。

Java Collections Framework 
Java集合类是一种工具类(特别有用)。Java集合大致可分为Set、List、Queue、Map四种体系。
Set代表无序、不可重复的集合;
List代表有序、可重复的集合;
Map代表具有映射关系的集合;
Queue代表一种队列集合实现(Java5新增的)


Java的集合主要是由两个接口派生而出:Collection和Map。(查阅java.util包)
Collection集合体系:

Map集合体系:

最常用的实现类:HashMap、ArrayList、HashSet及次之的LinkedList、TreeSet、ArrayDeque、TreeMap

Collection接口
看API文档
public interfaceCollection<E> extends Iterable<E>

所有的方法:无非是增删改查。
方法摘要booleanadd(E e)
该方法用于向集合中添加一个元素, 如果此 collection 由于调用而发生更改,则返回 true,很多情况下会抛出异常,详看文档booleanaddAll(Collection<? extends E> c)
将集合c中的所有元素都添加到此 collection 中。voidclear()
移除此集合中的所有元素,集合长度将变为0。booleancontains(Object o)
如果此 collection 包含指定的元素,则返回 true。booleancontainsAll(Collection<?> c)
如果此集合包含集合c中的所有元素,则返回 true。booleanequals(Object o)
比较此 collection 与指定对象是否相等。inthashCode()
返回此 collection 的哈希码值。booleanisEmpty()
如果此 collection 不包含元素,则返回 true。Iterator<E>iterator()
返回在此集合上的迭代器。 关于元素返回的顺序没有任何保证(除非此 collection 是某个能提供保证顺序的类实例),此方法来自于Iterable<E> 接口。booleanremove(Object o)
从此集合中移除指定元素o,如果此集合中有多个元素o,则只会删除第一个。booleanremoveAll(Collection<?> c)
从此集合中删除集合c中的所有元素(差集), 如果此 collection 由于调用而发生更改,则返回 truebooleanretainAll(Collection<?> c)
仅保留此集合中那些也包含在指定集合c中的元素(交集)。intsize()
返回此 collection 中的元素数。Object[]toArray()
把集合转换成一个数组。<T> T[]toArray(T[] a)
返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。

示例代码:
import java.util.*;

public class CollectionTest
{
public static void main(String[] args)
{
Collection c = new ArrayList();
// 添加元素
c.add("孙悟空");
// 虽然集合里不能放基本类型的值,但Java支持自动装箱
c.add(6);
System.out.println("c集合的元素个数为:" + c.size()); // 输出2
// 删除指定元素
c.remove(6);
System.out.println("c集合的元素个数为:" + c.size()); // 输出1
// 判断是否包含指定字符串
System.out.println("c集合的是否包含\"孙悟空\"字符串:"
+ c.contains("孙悟空")); // 输出true
c.add("轻量级Java EE企业应用实战");
System.out.println("c集合的元素:" + c);
Collection books = new HashSet();
books.add("轻量级Java EE企业应用实战");
books.add("疯狂Java讲义");
System.out.println("c集合是否完全包含books集合?"
+ c.containsAll(books)); // 输出false
// 用c集合减去books集合里的元素
c.removeAll(books);
System.out.println("c集合的元素:" + c);
// 删除c集合里所有元素
c.clear();
System.out.println("c集合的元素:" + c);
// 控制books集合里只剩下c集合里也包含的元素
books.retainAll(c);
System.out.println("books集合的元素:" + books);
}
}

集合的遍历
方法一、原来只能通过iterator()方法获取集合的迭代器后再进行遍历的,现在Java8给Iterable接口新增了一个forEach(Consumer<? super T> action)方法,而Collection又是实现了Iterable接口的,该方法所需的参数是一个函数式接口(只有一个抽象方法),因此可以用Lambda表达式。当调用Iterable的forEach(Consumer action)遍历集合时,程序会依次将集合元素传递给Consumer的accept(T t)方法。

示例代码:

import java.util.*;

public class CollectionEach
{
public static void main(String[] args)
{
// 创建一个集合
Collection books = new HashSet();
books.add("轻量级Java EE企业应用实战");
books.add("疯狂Java讲义");
books.add("疯狂Android讲义");
// 调用forEach()方法遍历集合
books.forEach(obj -> System.out.println("迭代集合元素:" + obj));
}
}

遍历方法二、使用传统的Iterator。
Iterator接口隐藏了各种Collection实现类的底层细节,向外提供了遍历Collection元素的统一编程接口。
Iterator接口也是Java集合框架的成员,但它与Collection系列、Map系列的集合不一样:Collection系列集合、Map系列集合主要用于盛装其他对象,而Iterator则主要用于遍历(即迭代访问)Collection集合中的元素,Iterator对象也被称为迭代器。
public interfaceIterator<E>
方法摘要booleanhasNext()
如果仍有元素可以迭代,则返回 true。Enext()
返回迭代的下一个元素。voidremove()
从迭代器指向的集合中移除迭代器返回的最后一个元素(上一次next返回的元素)。default voidforEachRemaining(Consumer<? super E> action)
Performs the given action for each remaining element until all elements have been processed or the action throws an exception.
这是Java8新增的方法,可以用Lambda表达式来遍历。

示例代码:

import java.util.*;

public class IteratorTest
{
public static void main(String[] args)
{
// 创建集合、添加元素的代码与前一个程序相同
Collection books = new HashSet();
books.add("轻量级Java EE企业应用实战");
books.add("疯狂Java讲义");
books.add("疯狂Android讲义");
// 获取books集合对应的迭代器
Iterator it = books.iterator();
while(it.hasNext())
{
// it.next()方法返回的数据类型是Object类型,因此需要强制类型转换
String book = (String)it.next();
System.out.println(book);
if (book.equals("疯狂Java讲义"))
{
// 从集合中删除上一次next方法返回的元素
it.remove();
// 使用Iterator迭代过程中,不可修改集合元素,下面代码引发异常
books.remove(book); //此行代码将引发ConcurrentModificationException异常
}
// 对book变量赋值,不会改变集合元素本身
book = "测试字符串"; //①
}
System.out.println(books);
}
}

使用forEachRemaining(Consumer<? super E> action)遍历集合:

import java.util.*;

public class IteratorEach
{
public static void main(String[] args)
{
// 创建集合、添加元素的代码与前一个程序相同
Collection books = new HashSet();
books.add("轻量级Java EE企业应用实战");
books.add("疯狂Java讲义");
books.add("疯狂Android讲义");
// 获取books集合对应的迭代器
Iterator it = books.iterator();
// 使用Lambda表达式(目标类型是Comsumer)来遍历集合元素
it.forEachRemaining(obj -> System.out.println("迭代集合元素:" + obj));
}
}


遍历方法三:使用Java5新增的foreach遍历也挺简单的
示例代码:

import java.util.*;

public class ForeachTest
{
public static void main(String[] args)
{
// 创建集合、添加元素的代码与前一个程序相同
Collection books = new HashSet();
books.add(new String("轻量级Java EE企业应用实战"));
books.add(new String("疯狂Java讲义"));
books.add(new String("疯狂Android讲义"));
for (Object obj : books)
{
// 此处的book变量也不是集合元素本身
String book = (String)obj;
System.out.println(book);
if (book.equals("疯狂Android讲义"))
{
// 下面代码会引发ConcurrentModificationException异常
books.remove(book); //①
}
}
System.out.println(books);
}
}

注意:1、和使用迭代器一样,循环中的迭代变量也不是集合元素本身,只是以此把集合元素的赋给迭代变量,对此变量进行修改不会影响集合本身。2、循环时不能改变集合,否则将引发ConcurrentModificationException异常


Java8为Collection集合新增了一个removeIf(Predicate filter)方法,该方法将会批量删除符合filter条件的所有元素。该方法的参数是一个Predicate对象,Predicate是一个函数式接口,可使用Lambda表达式。

示例代码:

import java.util.*;
import java.util.function.*;

public class PredicateTest
{
public static void main(String[] args)
{
// 创建一个集合
Collection books = new HashSet();
books.add(new String("轻量级Java EE企业应用实战"));
books.add(new String("疯狂Java讲义"));
books.add(new String("疯狂iOS讲义"));
books.add(new String("疯狂Ajax讲义"));
books.add(new String("疯狂Android讲义"));
// 使用Lambda表达式(目标类型是Predicate)过滤集合
books.removeIf(ele -> ((String)ele).length() < 10);
System.out.println(books);
}
}

使用Predicate可以简化集合的运算:将原来需要多次循环才能完成的事变成使用一个方法即可,
示例代码:(三个统计需求)

import java.util.*;
import java.util.function.*;

public class PredicateTest2
{
public static void main(String[] args)
{
// 创建books集合、为books集合添加元素的代码与前一个程序相同。
Collection books = new HashSet();
books.add(new String("轻量级Java EE企业应用实战"));
books.add(new String("疯狂Java讲义"));
books.add(new String("疯狂iOS讲义"));
books.add(new String("疯狂Ajax讲义"));
books.add(new String("疯狂Android讲义"));
// 统计书名包含“疯狂”子串的图书数量
System.out.println(calAll(books , ele->((String)ele).contains("疯狂")));
// 统计书名包含“Java”子串的图书数量
System.out.println(calAll(books , ele->((String)ele).contains("Java")));
// 统计书名字符串长度大于10的图书数量
System.out.println(calAll(books , ele->((String)ele).length() > 10));
}
public static int calAll(Collection books , Predicate p)
{
int total = 0;
for (Object obj : books)
{
// 使用Predicate的test()方法判断该对象是否满足Predicate指定的条件
if (p.test(obj))
{
total ++;
}
}
return total;
}
}


Java 8新增了Stream、IntStream、LongStream、DoubleStream等流式API来操作集合,这些API代表多个支持串行和并行聚集操作的元素。Stream是一个通用的流接口。
Stream等流式API貌似没有构造函数,但是Java8为每个API提供了对应的Builder,如Stream.Builder、IntStream.Builder,只能通过这些Builder来创建对应的流。
独立使用Stream的步骤如下:
(1)使用Stream或XxxStream的builder()类方法创建该Stream对应Builder。
(2)重复调用Builder的add()方法向该流中添加多个元素。
(3)调用Builder的build()方法获取对应的Stream。
(4)调用Stream的聚集方法。

示例代码:

import java.util.stream.*;

public class IntStreamTest
{
public static void main(String[] args)
{
IntStream is = IntStream.builder()
.add(20)
.add(13)
.add(-2)
.add(18)
.build();
// 下面调用聚集方法的代码每次只能执行一个
System.out.println("is所有元素的最大值:" + is.max().getAsInt());
System.out.println("is所有元素的最小值:" + is.min().getAsInt());
System.out.println("is所有元素的总和:" + is.sum());
System.out.println("is所有元素的总数:" + is.count());
System.out.println("is所有元素的平均值:" + is.average());
System.out.println("is所有元素的平方是否都大于20:"
+ is.allMatch(ele -> ele * ele > 20));
System.out.println("is是否包含任何元素的平方大于20:"
+ is.anyMatch(ele -> ele * ele > 20));
// 将is映射成一个新Stream,新Stream的每个元素是原Stream元素的2倍+1
IntStream newIs = is.map(ele -> ele * 2 + 1);
// 使用方法引用的方式来遍历集合元素
newIs.forEach(System.out::println); // 输出41 27 -3 37
}
}

Stream提供了大量的方法进行聚合操作,这些方法既可以是“中间的”(intermediate)操作,也可以是“末端的”(terminal)操作。
中间方法:中间操作允许流保持打开状态,并允许直接调用后续方法。中间方法的返回值是另外一个流。如map()方法。
末端方法:末端方法是对流的最终操作。如sum()、count()。

Stream常用的中间方法:
Stream<T>filter(Predicate<? super T> predicate)
Returns a stream consisting of the elements of this stream that match the given predicate.返回符合条件的元素。<R> Stream<R>map(Function<? super T,? extends R> mapper)
Returns a stream consisting of the results of applying the given function to the elements of this stream.DoubleStreammapToDouble(ToDoubleFunction<? super T> mapper)Returns a DoubleStream consisting of the results of applying the given function to the elements of this stream.IntStreammapToInt(ToIntFunction<? super T> mapper)Returns an IntStream consisting of the results of applying the given function to the elements of this stream.LongStreammapToLong(ToLongFunction<? super T> mapper)Returns a LongStream consisting of the results of applying the given function to the elements of this stream.Streampeek(Consumer action)
依次对每个元素执行一些操作,该方法返回的流与原始流包含相同的元素,该方法主要用于调试。Streamdistinct()
Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this streamStreamsorted()
Returns a stream consisting of the elements of this stream, sorted according to natural order.Streamlimit(long maxSize)
该方法用于保证对该流的后续操作中最大允许访问的元素个数。


Stream常用的末端方法:
voidforEach(Consumer<? super T> action)
遍历流中的所有元素,对每个流执行action操作Object[]toArray()
将流中的所有元素转化为一个数组Optional<T>reduce(BinaryOperator<T> accumulator)Performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any.Treduce(T identity, BinaryOperator<T> accumulator)Performs a reduction on the elements of this stream, using the provided identity value and anassociative accumulation function, and returns the reduced value.<U> Ureduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)Performs a reduction on the elements of this stream, using the provided identity, accumulation and combining functions.Optional<T>min(Comparator<? super T> comparator)
返回流中所有元素的最小值Optional<T>max(Comparator<? super T> comparator)
返回流中所有元素的最大值longcount()
返回流中所有元素的数量booleanallMatch(Predicate<? super T> predicate)  
判断流中是否每个元素都符合Predicate条件。booleananyMatch(Predicate<? super T> predicate)  
判断流中是否至少存在一个元素符合Predicate条件。booleannoneMatch(Predicate<? super T> predicate)  
判断流中是否所有元素都不符合Predicate条件。Optional<T>findFirst()
返回流中的第一个元素Optional<T>findAny() 
 返回流中的任意一个元素

Collection接口提供了一个stream()默认方法,该方法可返回该集合对应的流,接下来即可通过流API来操作集合元素。由于Stream可以对集合元素进行整体的聚集操作,因此Stream极大了丰富了集合的功能。
示例代码:(改进了上一个使用Predicate来统计数量的程序PredicateTest2)

import java.util.*;
import java.util.function.*;

public class CollectionStream
{
public static void main(String[] args)
{
// 创建books集合、为books集合添加元素的代码与8.2.5小节的程序相同。
Collection books = new HashSet();
books.add(new String("轻量级Java EE企业应用实战"));
books.add(new String("疯狂Java讲义"));
books.add(new String("疯狂iOS讲义"));
books.add(new String("疯狂Ajax讲义"));
books.add(new String("疯狂Android讲义"));
// 统计书名包含“疯狂”子串的图书数量
System.out.println(books.stream()
.filter(ele->((String)ele).contains("疯狂"))
.count()); // 输出4
// 统计书名包含“Java”子串的图书数量
System.out.println(books.stream()
.filter(ele->((String)ele).contains("Java") )
.count()); // 输出2
// 统计书名字符串长度大于10的图书数量
System.out.println(books.stream()
.filter(ele->((String)ele).length() > 10)
.count()); // 输出2
// 先调用Collection对象的stream()方法将集合转换为Stream,
// 再调用Stream的mapToInt()方法获取原有的Stream对应的IntStream
books.stream().mapToInt(ele -> ((String)ele).length())
// 调用forEach()方法遍历IntStream中每个元素
.forEach(System.out::println);// 输出8 11 16 7 8
}
}


-----------------------------------------------------------
Set集合:无序、不可重复。
HashSet:
1、集合元素可以是null;
2、不是同步的,如果多个线程同时修改同一个HashSet,则必须通过代码来保证其同步。
3、按hash算法来存储元素,具有很好的存取和查找性能。

当向HashSet中存入元素时,HashSet会调用该对象的hashCode()方法来获取该对象的hashCode值,然后决定该对象在HashSet中的位置。
HashSet判断两个元素相等的标准是两个对象的equal()方法比较相等,且hashCode()方法返回值也相等。

示例代码:

import java.util.*;

// 类A的equals方法总是返回true,但没有重写其hashCode()方法
class A
{
public boolean equals(Object obj)
{
return true;
}
}
// 类B的hashCode()方法总是返回1,但没有重写其equals()方法
class B
{
public int hashCode()
{
return 1;
}
}
// 类C的hashCode()方法总是返回2,且重写其equals()方法总是返回true
class C
{
public int hashCode()
{
return 2;
}
public boolean equals(Object obj)
{
return true;
}
}
public class HashSetTest
{
public static void main(String[] args)
{
HashSet books = new HashSet();
// 分别向books集合中添加两个A对象,两个B对象,两个C对象
books.add(new A());
books.add(new A());
books.add(new B());
books.add(new B());
books.add(new C());
books.add(new C());
System.out.println(books);
}
}

将可变对象添加到了HashSet中之后,尽量不要去修改该元素参与equal()和hashCode()计算的实例变量,否则将会导致HashSet无法正确操作这些集合元素。
示例代码:

import java.util.*;

class R
{
int count;
public R(int count)
{
this.count = count;
}
public String toString()
{
return "R[count:" + count + "]";
}
public boolean equals(Object obj)
{
if(this == obj)
return true;
if (obj != null && obj.getClass() == R.class)
{
R r = (R)obj;
return this.count == r.count;
}
return false;
}
public int hashCode()
{
return this.count;
}
}
public class HashSetTest2
{
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add(new R(5));
hs.add(new R(-3));
hs.add(new R(9));
hs.add(new R(-2));
// 打印HashSet集合,集合元素没有重复
System.out.println(hs);
// 取出第一个元素
Iterator it = hs.iterator();
R first = (R)it.next();
// 为第一个元素的count实例变量赋值
first.count = -3; // ①
// 再次输出HashSet集合,集合元素有重复元素
System.out.println(hs);
// 删除count为-3的R对象
hs.remove(new R(-3)); // ②
// 可以看到被删除了一个R元素
System.out.println(hs);
System.out.println("hs是否包含count为-3的R对象?"
+ hs.contains(new R(-3))); // 输出false
System.out.println("hs是否包含count为-2的R对象?"
+ hs.contains(new R(-2))); // 输出false
}
}


LinkedHashSet:HashSet的子类,看名字就知道。LinkedHashSet集合也是根据元素的hashCode值来决定元素的位置的,但他同时使用了链表维护元素的次序,因此其性能略低于HashSet。
示例代码:

import java.util.*;

public class LinkedHashSetTest
{
public static void main(String[] args)
{
LinkedHashSet books = new LinkedHashSet();
books.add("疯狂Java讲义");
books.add("轻量级Java EE企业应用实战");
System.out.println(books);
// 删除 疯狂Java讲义
books.remove("疯狂Java讲义");
// 重新添加 疯狂Java讲义
books.add("疯狂Java讲义");
System.out.println(books);
}
}

TreeSet:SortedSet接口的实现。功能如其名:元素处于排序状态。
TreeSet采用红黑树的数据结构来存储集合元素,TreeSet支持两种排序方法:自然排序和定制排序。
TreeSet提供的额外方法:
Comparator<? super E>comparator()
返回对此 set 中的元素进行排序的比较器;如果此 set 使用其元素的自然顺序,则返回 null。Efirst() 
          返回此 set 中当前第一个(最低)元素。Elast() 
          返回此 set 中当前最后一个(最高)元素。Elower(E e) 
          返回此 set 中严格小于给定元素(参考元素不需要是TreeSet集合中的元素)的最大元素;如果不存在这样的元素,则返回 null。Ehigher(E e) 
          返回此 set 中严格大于给定元素 (参考元素不需要是TreeSet集合中的元素)  的最小元素;如果不存在这样的元素,则返回 null。 SortedSet<E>headSet(E toElement) 
          返回此 set 的子集,由小于 toElement的元素组成。 SortedSet<E>tailSet(E fromElement)c           
返回此 set 的子集,由大于或等于fromElement的元素组成。 SortedSet<E>subSet(E fromElement, E toElement) 
          返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)。
示例代码:

import java.util.*;

public class TreeSetTest
{
public static void main(String[] args)
{
TreeSet nums = new TreeSet();
// 向TreeSet中添加四个Integer对象
nums.add(5);
nums.add(2);
nums.add(10);
nums.add(-9);
// 输出集合元素,看到集合元素已经处于排序状态
System.out.println(nums);
// 输出集合里的第一个元素
System.out.println(nums.first()); // 输出-9
// 输出集合里的最后一个元素
System.out.println(nums.last()); // 输出10
// 返回小于4的子集,不包含4
System.out.println(nums.headSet(4)); // 输出[-9, 2]
// 返回大于5的子集,如果Set中包含5,子集中还包含5
System.out.println(nums.tailSet(5)); // 输出 [5, 10]
// 返回大于等于-3,小于4的子集。
System.out.println(nums.subSet(-3 , 4)); // 输出[2]
}
}

自然排序:TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间大小关系,然后将集合元素按升序排列,这种方式就是自然排列。
定制排序:TreeSet借助于Comparator接口的帮助。该接口里包含一个的int compare(T o1, T o2)方法,该方法用于比较o1和o2的大小。

compareTo是Comparable接口的方法,obj1.compare(obj2),如果返回0则说明两个对象相等,如果返回正整数则说明obj1大于obj2,如果返回负整数,则obj2大于obj1。
java的一些常用类已实现了Comparable接口。
如果要把一个对象添加到TreeSet中,则该对象必须实现Comparable接口,且得是同一个类型的对象。否则报错ClassCastException。

不要修改放入TreeSet中的元素。

定制排序:在构造TreeSet时就指定比较器。publicTreeSet(Comparator<? superE> comparator)
Comparator是一个函数式接口,可使用Lambda表达式。
示例代码:

import java.util.*;

class M
{
int age;
public M(int age)
{
this.age = age;
}
public String toString()
{
return "M[age:" + age + "]";
}
}
public class TreeSetTest4
{
public static void main(String[] args)
{
// 此处Lambda表达式的目标类型是Comparator
TreeSet ts = new TreeSet((o1 , o2) ->
{
M m1 = (M)o1;
M m2 = (M)o2;
// 根据M对象的age属性来决定大小,age越大,M对象反而越小
return m1.age > m2.age ? -1
: m1.age < m2.age ? 1 : 0;
});
ts.add(new M(5));
ts.add(new M(-3));
ts.add(new M(9));
System.out.println(ts);
}
}

EnumSet
EnumSet是一个专为枚举类设计的集合类,EnumSet中所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式或隐式地指定。EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类的定义顺序来决定集合元素的顺序。
EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑、高效,因此EnumSet对象占用内存很小,而且运行效率很好。尤其是当进行批量操作(如调用containsAll 和 retainAll方法)时,如其参数也是EnumSet集合,则该批量操作的执行速度也非常快。
EnumSet集合不允许加入null元素。如果试图插入null元素,EnumSet将抛出 NullPointerException异常。如果仅仅只是试图测试是否出现null元素、或删除null元素都不会抛出异常,只是删除操作将返回false,因为没有任何null元素被删除。

EnumSet没有暴露任何构造器来创建该类的实例,只能通过它提供的类方法来创建EnumSet实例,常用方法有:
EnumSet allOf(Class<E> elementType) 
          创建一个包含指定枚举类型里所有枚举值的EnumSet集合
EnumSet complementOf(EnumSet<E> s) 
          创建一个其元素类型与指定EnumSet相同的EnumSet,新EnumSet包含原EnumSet集合所不包含的枚举值
EnumSet copyOf(Collection<E> c) 
          创建一个从指定 collection 初始化的枚举 set。
EnumSet copyOf(EnumSet<E> s) 
          创建一个其元素类型与指定EnumSet具有相同的枚举值的EnumSet
EnumSet noneOf(Class<E> elementType) 
          创建一个具有指定元素类型的空枚举 set。
EnumSet of(E first, E... rest) 
          创建一个最初包含指定元素的枚举 set。
EnumSet range(E from, E to) 
          创建一个最初包含由两个指定端点所定义范围内的所有元素的枚举 set。

示例代码:

import java.util.*;

enum Season
{
SPRING,SUMMER,FALL,WINTER
}
public class EnumSetTest
{
public static void main(String[] args)
{
// 创建一个EnumSet集合,集合元素就是Season枚举类的全部枚举值
EnumSet es1 = EnumSet.allOf(Season.class);
System.out.println(es1); // 输出[SPRING,SUMMER,FALL,WINTER]
// 创建一个EnumSet空集合,指定其集合元素是Season类的枚举值。
EnumSet es2 = EnumSet.noneOf(Season.class);
System.out.println(es2); // 输出[]
// 手动添加两个元素
es2.add(Season.WINTER);
es2.add(Season.SPRING);
System.out.println(es2); // 输出[SPRING,WINTER]
// 以指定枚举值创建EnumSet集合
EnumSet es3 = EnumSet.of(Season.SUMMER , Season.WINTER);
System.out.println(es3); // 输出[SUMMER,WINTER]
EnumSet es4 = EnumSet.range(Season.SUMMER , Season.WINTER);
System.out.println(es4); // 输出[SUMMER,FALL,WINTER]
// 新创建的EnumSet集合的元素和es4集合的元素有相同类型,
// es5的集合元素 + es4集合元素 = Season枚举类的全部枚举值
EnumSet es5 = EnumSet.complementOf(es4);
System.out.println(es5); // 输出[SPRING]
}
}



import java.util.*;

public class EnumSetTest2
{
public static void main(String[] args)
{
Collection c = new HashSet();
c.clear();
c.add(Season.FALL);
c.add(Season.SPRING);
// 复制Collection集合中所有元素来创建EnumSet集合
EnumSet enumSet = EnumSet.copyOf(c); // ①
System.out.println(enumSet); // 输出[SPRING,FALL]
c.add("疯狂Java讲义");
c.add("轻量级Java EE企业应用实战");
// 下面代码出现异常:因为c集合里的元素不是全部都为枚举值
enumSet = EnumSet.copyOf(c); // ②
}
}

----------------------------------------------------------------------------
List:有序、可重复
List中添加了一些通过索引操作List的方法。
voidadd(int index, E element)
在列表的指定位置index插入指定元素。booleanaddAll(int index, Collection<? extends E> c) 
          将指定 collection 中的所有元素都插入到列表中的指定位置。 Eget(int index) 
          返回列表中指定位置的元素。intindexOf(Object o) 
          返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。intlastIndexOf(Object o) 
          返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。booleanremove(Object o) 
          从此列表中移除第一次出现的指定元素(如果存在)。 Eset(int index, E element) 
          用指定元素替换列表中指定位置的元素。 List<E>subList(int fromIndex, int toIndex) 
          返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。voidsort(Comparator<? super E> c)
根据Comparator对List集合进行排序(Java8新增的方法)voidreplaceAll(UnaryOperator<E> operator)
根据operator指定的计算规则重新设置list集合的所有元素(Java8) ListIterator<E>listIterator() 
          返回此列表元素的列表迭代器(按适当顺序)。 ListIterator<E>listIterator(int index) 
          返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
示例代码:

import java.util.*;

public class ListTest
{
public static void main(String[] args)
{
List books = new ArrayList();
// 向books集合中添加三个元素
books.add(new String("轻量级Java EE企业应用实战"));
books.add(new String("疯狂Java讲义"));
books.add(new String("疯狂Android讲义"));
System.out.println(books);
// 将新字符串对象插入在第二个位置
books.add(1 , new String("疯狂Ajax讲义"));
for (int i = 0 ; i < books.size() ; i++ )
{
System.out.println(books.get(i));
}
// 删除第三个元素
books.remove(2);
System.out.println(books);
// 判断指定元素在List集合中位置:输出1,表明位于第二位
System.out.println(books.indexOf(new String("疯狂Ajax讲义"))); //①
//将第二个元素替换成新的字符串对象
books.set(1, new String("疯狂Java讲义"));
System.out.println(books);
//将books集合的第二个元素(包括)
//到第三个元素(不包括)截取成子集合
System.out.println(books.subList(1 , 2));
}
}

List判断两个对象相等的是equal()方法
示例代码:

import java.util.*;

class A
{
public boolean equals(Object obj)
{
return true;
}
}
public class ListTest2
{
public static void main(String[] args)
{
List books = new ArrayList();
books.add(new String("轻量级Java EE企业应用实战"));
books.add(new String("疯狂Java讲义"));
books.add(new String("疯狂Android讲义"));
System.out.println(books);
// 删除集合中A对象,将导致第一个元素被删除
books.remove(new A()); // ①
System.out.println(books);
// 删除集合中A对象,再次删除集合中第一个元素
books.remove(new A()); // ②
System.out.println(books);
}
}

Java8新增的方法:

import java.util.*;

public class ListTest3
{
public static void main(String[] args)
{
List books = new ArrayList();
// 向books集合中添加4个元素
books.add(new String("轻量级Java EE企业应用实战"));
books.add(new String("疯狂Java讲义"));
books.add(new String("疯狂Android讲义"));
books.add(new String("疯狂iOS讲义"));
// 使用目标类型为Comparator的Lambda表达式对List集合排序
books.sort((o1, o2)->((String)o1).length() - ((String)o2).length());
System.out.println(books);
// 使用目标类型为UnaryOperator的Lambda表达式来替换集合中所有元素
// 该Lambda表达式控制使用每个字符串的长度作为新的集合元素
books.replaceAll(ele->((String)ele).length());
System.out.println(books); // 输出[7, 8, 11, 16]
}
}

List额外的方法listIterator()返回的ListIterator接口对象,提供了专门操作List的方法,它不仅可以向后迭代,它还可以向前迭代:
boolean hasPrevious():返回该迭代器关联的集合是否还有上一个元素。
Object previous():返回该迭代器的上一个元素。
void add():在指定位置插入一个元素
示例代码:

import java.util.*;

public class ListIteratorTest
{
public static void main(String[] args)
{
String[] books = {
"疯狂Java讲义", "疯狂iOS讲义",
"轻量级Java EE企业应用实战"
};
List bookList = new ArrayList();
for (int i = 0; i < books.length ; i++ )
{
bookList.add(books[i]);
}
ListIterator lit = bookList.listIterator();
while (lit.hasNext())
{
System.out.println(lit.next());
lit.add("-------分隔符-------");
}
System.out.println("=======下面开始反向迭代=======");
while(lit.hasPrevious())
{
System.out.println(lit.previous());
}
}
}


ArrayList和Vector实现类
都是基于数组实现的List类,都是封装了一个动态的、允许再分配的Object[]数组,使用initialCapacity参数来设置该数组的长度,当添加的元素超出了该数组的长度时,它们的initialCapacity会自动增加。如果开始就知道ArrayList或Vector集合需要保存的元素个数,则可以在创建他们时就指定initialCapacity大小,如果不指定默认为10。
Vector是一个古老的集合类(从JDK1.0开始就有了),那时候还没有提供系统的集合框架,从JDK1.2以后才提供系统的集合框架,于是将Vector改为了实现List接口,导致了Vector里面有一些功能重复的方法。
ArrayList是线程不安全的,Vector是线程安全的。所以Vector的性能比ArrayList低。即使要保证线程安全,也不推荐使用Vector,而是推荐使用Collections工具类来将ArrayList集合变成线程安全的。
Vector有一个Stack子类,它用于模拟“栈”这种数据结构。同样,Stack也是线程安全、性能较差的,不推荐使用,而是用ArrayDeque代替。

固定长度的List
Arrays.ArrayList
Arrays工具类里提供了asList(Object... a)方法,该方法可以把一个数组、或指定个数的对象转换成一个List集合,这个List集合既不是ArrayList实现类的实例,也不是Vector实现类的实例,而是Arrays的内部类ArrayList的实例。Arrays.ArrayList是一个固定长度的List集合,程序只能遍历访问该集合里的元素,不可增加、删除该集合里的元素

示例代码:

import java.util.*;

public class FixedSizeList
{
public static void main(String[] args)
{
List fixedList = Arrays.asList("疯狂Java讲义"
, "轻量级Java EE企业应用实战");
// 获取fixedList的实现类,将输出Arrays$ArrayList
System.out.println(fixedList.getClass());
// 使用方法引用遍历集合元素
fixedList.forEach(System.out::println);
// 试图增加、删除元素都会引发UnsupportedOperationException异常
fixedList.add("疯狂Android讲义");
fixedList.remove("疯狂Java讲义");
}
}

--------------------------------------------------------------------
Queue:队列集合
Queue是模拟队列的数据结构,队列是先进先出(FIFO)的容器。
Queue的方法:
方法摘要booleanadd(E e)
将指定元素插入此队列的尾部。 在成功时返回 true,如果当前没有可用的空间,则抛出IllegalStateException。 Eelement() 
          获取队列头部的元素,但是不移除此元素。booleanoffer(E e) 
          将指定的元素插入此队列,当使用有容量限制的队列时,此方法通常要优于add(E),后者可能无法插入元素,而只是抛出一个异常。 Epeek() 
          获取但不移除此队列的头;如果此队列为空,则返回 null。 Epoll() 
          获取并移除此队列的头,如果此队列为空,则返回 null。 Eremove() 
          获取并移除此队列的头。

PriorityQueue:Queue的实现,将添加的元素进行了排序。
示例代码:

import java.util.*;

public class PriorityQueueTest
{
public static void main(String[] args)
{
PriorityQueue pq = new PriorityQueue();
// 下面代码依次向pq中加入四个元素
pq.offer(6);
pq.offer(-3);
pq.offer(20);
pq.offer(18);
// 输出pq队列,并不是按元素的加入顺序排列
System.out.println(pq); // 输出[-3, 6, 20, 18]
// 访问队列第一个元素,其实就是队列中最小的元素:-3
System.out.println(pq.poll());
}
}

PriorityQueue的元素有两种排序方式:
1、自然排序:元素必须实现Comparable接口,且得是同一类的实例。
2、定制排序:创建PriorityQueue时传入一个Comparator对象,该对象负责对队列中所有的元素进行排序。
两种排序的用法与TreeSet一样,参考TreeSet即可。

Deque接口与ArrayDeque实现类
Deuqe接口代表一个双端队列:可以从队列两端来操作队列。
新增的操作首尾元素的方法:
方法摘要voidaddFirst(E e)
将指定元素插入此双端队列的开头(如果可以直接这样做而不违反容量限制)。voidaddLast(E e)
将指定元素插入此双端队列的末尾(如果可以直接这样做而不违反容量限制)。Iterator<E>descendingIterator()
返回以逆向顺序在此双端队列的元素上进行迭代的迭代器。EgetFirst()
获取,但不移除此双端队列的第一个元素。EgetLast()
获取,但不移除此双端队列的最后一个元素。Iterator<E>iterator()
返回以恰当顺序在此双端队列的元素上进行迭代的迭代器。booleanofferFirst(E e)
在不违反容量限制的情况下,将指定的元素插入此双端队列的开头。booleanofferLast(E e)
在不违反容量限制的情况下,将指定的元素插入此双端队列的末尾。EpeekFirst()
获取,但不移除此双端队列的第一个元素;如果此双端队列为空,则返回 null。EpeekLast()
获取,但不移除此双端队列的最后一个元素;如果此双端队列为空,则返回 null。EpollFirst()
获取并移除此双端队列的第一个元素;如果此双端队列为空,则返回 null。EpollLast()
获取并移除此双端队列的最后一个元素;如果此双端队列为空,则返回 null。Epop()  栈方法
从此双端队列所表示的堆栈中弹出一个栈顶的元素。相当于removeFirst()方法voidpush(E e)    栈方法  
将一个元素推入此双端队列所表示的栈顶(此双端队列的头部),相当于addFirst()Eremove()
获取并移除此双端队列所表示的队列的头部(换句话说,此双端队列的第一个元素)。booleanremove(Object o)
从此双端队列中移除第一次出现的指定元素。EremoveFirst()
获取并移除此双端队列第一个元素。booleanremoveFirstOccurrence(Object o)
从此双端队列移除第一次出现的指定元素。EremoveLast()
获取并移除此双端队列的最后一个元素。booleanremoveLastOccurrence(Object o)
从此双端队列移除最后一次出现的指定元素。

示例代码:队列的使用

import java.util.*;

public class ArrayDequeQueue
{
public static void main(String[] args)
{
ArrayDeque queue = new ArrayDeque();
// 依次将三个元素加入队列
queue.offer("疯狂Java讲义");
queue.offer("轻量级Java EE企业应用实战");
queue.offer("疯狂Android讲义");
// 输出:[疯狂Java讲义, 轻量级Java EE企业应用实战, 疯狂Android讲义]
System.out.println(queue);
// 访问队列头部的元素,但并不将其poll出队列"栈",输出:疯狂Java讲义
System.out.println(queue.peek());
// 依然输出:[疯狂Java讲义, 轻量级Java EE企业应用实战, 疯狂Android讲义]
System.out.println(queue);
// poll出第一个元素,输出:疯狂Java讲义
System.out.println(queue.poll());
// 输出:[轻量级Java EE企业应用实战, 疯狂Android讲义]
System.out.println(queue);
}
}

示例代码:栈的使用
import java.util.*;

public class ArrayDequeStack
{
public static void main(String[] args)
{
ArrayDeque stack = new ArrayDeque();
// 依次将三个元素push入"栈"
stack.push("疯狂Java讲义");
stack.push("轻量级Java EE企业应用实战");
stack.push("疯狂Android讲义");
// 输出:[疯狂Android讲义, 轻量级Java EE企业应用实战, 疯狂Java讲义]
System.out.println(stack);
// 访问第一个元素,但并不将其pop出"栈",输出:疯狂Android讲义
System.out.println(stack.peek());
// 依然输出:[疯狂Android讲义, 疯狂Java讲义, 轻量级Java EE企业应用实战]
System.out.println(stack);
// pop出第一个元素,输出:疯狂Android讲义
System.out.println(stack.pop());
// 输出:[轻量级Java EE企业应用实战, 疯狂Java讲义]
System.out.println(stack);
}
}

LinkedList实现类:可作为List集合、双端队列、栈来使用。
public classLinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable

示例代码:

import java.util.*;

public class LinkedListTest
{
public static void main(String[] args)
{
LinkedList books = new LinkedList();
// 将字符串元素加入队列的尾部
books.offer("疯狂Java讲义");
// 将一个字符串元素加入栈的顶部
books.push("轻量级Java EE企业应用实战");
// 将字符串元素添加到队列的头部(相当于栈的顶部)
books.offerFirst("疯狂Android讲义");
// 以List的方式(按索引访问的方式)来遍历集合元素
for (int i = 0; i < books.size() ; i++ )
{
System.out.println("遍历中:" + books.get(i));
}
// 访问、并不删除栈顶的元素
System.out.println(books.peekFirst());
// 访问、并不删除队列的最后一个元素
System.out.println(books.peekLast());
// 将栈顶的元素弹出“栈”
System.out.println(books.pop());
// 下面输出将看到队列中第一个元素被删除
System.out.println(books);
// 访问、并删除队列的最后一个元素
System.out.println(books.pollLast());
// 下面输出:[轻量级Java EE企业应用实战]
System.out.println(books);
}
}

==================================================

Map:


Map用于保存具有映射关系的数据,因此Map集合中保存着两组数据:一组数据保存着Map中的key,另一组保存着value。key不允许重复(重复是通过equal方法比较的)。

如果把Map中的所有key放在一起来看,它们就组成了一个Set集合,而实际上Map也确实提供了一个方法keySet()来获取所有key组成的Set集合。
Map中的key集与Set集合里元素的存储形式一样,从其子类的名字上即可看出:
Set:HashSet、LinkedHashSet、SortedSet、TreeSet、EnumSet
Map:HashMap、LinkedHashMap、SortedMap、TreeMap、EnumSet
Java先是实现了Map,后来从中抽取出来了Set集合。而Map中的value集就像是List集合,只不过索引不是整数值,而是key值。

Map集合提供的方法:
public interfaceMap<K,V>
方法摘要voidclear()
删除该map所有的key-value对。booleancontainsKey(Object key)
如果此map中包含指定key的映射关系,则返回 true。booleancontainsValue(Object value)
如果此map包含一个或多个指定的value,则返回 true。Set<Map.Entry<K,V>>entrySet()
返回此map中包含的映射关系所组成的Set集合,每个集合元素都是Map.Entry对象。Vget(Object key)
返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。booleanisEmpty()
如果此映射未包含键-值映射关系,则返回 true。Set<K>keySet()
返回此映射中包含的键的 Set 视图。Vput(K key, V value)
将指定的值与此映射中的指定键关联(可选操作)。voidputAll(Map<? extends K,? extends V> m)
从指定映射中将所有映射关系复制到此映射中(可选操作)。Vremove(Object key)
如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。intsize()
返回此映射中的键-值映射关系数。Collection<V>values()
返回此映射中包含的值的 Collection 视图。

Map接口中包含一个内部类Entry,该类封装了一个kay-value对,Entry包括三个方法:
KgetKey()
返回与此项对应的键。VgetValue()
返回与此项对应的值。VsetValue(V value)
用指定的值替换与此项对应的值。

Map的基本功能示例代码:

import java.util.*;

public class MapTest
{
public static void main(String[] args)
{
Map map = new HashMap();
// 成对放入多个key-value对
map.put("疯狂Java讲义" , 109);
map.put("疯狂iOS讲义" , 10);
map.put("疯狂Ajax讲义" , 79);
// 多次放入的key-value对中value可以重复
map.put("轻量级Java EE企业应用实战" , 99);
// 放入重复的key时,新的value会覆盖原有的value
// 如果新的value覆盖了原有的value,该方法返回被覆盖的value
System.out.println(map.put("疯狂iOS讲义" , 99)); // 输出10
System.out.println(map); // 输出的Map集合包含4个key-value对
// 判断是否包含指定key
System.out.println("是否包含值为 疯狂iOS讲义 key:"
+ map.containsKey("疯狂iOS讲义")); // 输出true
// 判断是否包含指定value
System.out.println("是否包含值为 99 value:"
+ map.containsValue(99)); // 输出true
// 获取Map集合的所有key组成的集合,通过遍历key来实现遍历所有key-value对
for (Object key : map.keySet() )
{
// map.get(key)方法获取指定key对应的value
System.out.println(key + "-->" + map.get(key));
}
map.remove("疯狂Ajax讲义"); // 根据key来删除key-value对。
System.out.println(map); // 输出结果不再包含 疯狂Ajax讲义=79 的key-value对
}
}


Java8为map新增的方法:
booleanremove(Object key, Object value)

Vcompute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction):该方法使用remappingFunction根据原key-value对计算一个新的value,如果新的value不为null,则使用新value覆盖原来的value;如果新value为null,但是原value不为null,则删除原key-value对;如果新value、原value同时为null,则该方法不做任何改变,直接返回null。

VcomputeIfAbsent(K key, Function<? super K,? extends V> mappingFunction):如果传给map的key对应的value为null,则使用mappingFunction根据key计算一个新的结果,如果计算的新结果不为null,则使用新结果覆盖原来的value;如果原map不包括该key,则添加一对key-value。

VcomputeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction):如果传给map的key对应的value不为null,则使用remappingFunction根据原key、value计算一个新的结果,如果计算的新结果不为null,则使用新结果覆盖原来的value;如果计算的结果为null,则删除原来的key-value对。

voidforEach(BiConsumer<? super K,? super V> action):遍历方法

VgetOrDefault(Object key, V defaultValue):根据key获取value,如果该key不存在,则返回defaultValue。

default Vmerge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction):
If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value.

VputIfAbsent(K key, V value)
If the specified key is not already associated with a value (or is mapped to null) associates it with the given value and returns null, else returns the current value.

Vreplace(K key, V value)
Replaces the entry for the specified key only if it is currently mapped to some value.

Vreplace(K key, V oldValue, V newValue)
Replaces the entry for the specified key only if currently mapped to the specified value.

voidreplaceAll(BiFunction<? super K,? super V,? extends V> function)
Replaces each entry's value with the result of invoking the given function on that entry until all entries have been processed or the function throws an exception.

示例代码:

import java.util.*;

public class MapTest2
{
public static void main(String[] args)
{
Map map = new HashMap();
// 成对放入多个key-value对
map.put("疯狂Java讲义" , 109);
map.put("疯狂iOS讲义" , 99);
map.put("疯狂Ajax讲义" , 79);
// 尝试替换key为"疯狂XML讲义"的value,由于原Map中没有对应的key,
// 因此对Map没有改变,不会添加新的key-value对
map.replace("疯狂XML讲义" , 66);
System.out.println(map);
// 使用原value与参数计算出来的结果覆盖原有的value
map.merge("疯狂iOS讲义" , 10 ,
(oldVal , param) -> (Integer)oldVal + (Integer)param);
System.out.println(map); // "疯狂iOS讲义"的value增大了10
// 当key为"Java"对应的value为null(或不存在时),使用计算的结果作为新value
map.computeIfAbsent("Java" , (key)->((String)key).length());
System.out.println(map); // map中添加了 Java=4 这组key-value对
// 当key为"Java"对应的value存在时,使用计算的结果作为新value
map.computeIfPresent("Java",
(key , value) -> (Integer)value * (Integer)value);
System.out.println(map); // map中 Java=4 变成 Java=16
}
}


HashMap和Hashtable的关系类似于ArrayList和Vector的关系,Hashtable也是一个古老的类(从JDK1.0开始)。Hashtable的名字都没有遵循规范,单词首字母大写。
Hashtable:线程安全,key、value都不能为null;(不推荐使用)
HashMap:线程不安全,key、value可以为null,性能较Hashtable好;
key对象必须实现equal()和hashCode()方法,与HashSet一样使用这两个方法判断key是否相等。操作map时不要修改其元素。

LinkedHashMap类似LinkedHashSet,使用链表来维护key集的次序(与插入顺序一致)。

使用Properties读写属性文件
Properties是Hashtable类的子类,用来处理属性文件,可以把Map和属性文件关联起来。可以读写属性文件。Properties相当于一个key、value都是String的Map。
public class Properties extendsHashtable<Object,Object>

方法摘要StringgetProperty(String key)
用指定的键在此属性列表中搜索属性。StringgetProperty(String key, String defaultValue)
用指定的键在属性列表中搜索属性。voidlist(PrintStream out)
将属性列表输出到指定的输出流。voidlist(PrintWriter out)
将属性列表输出到指定的输出流。voidload(InputStream inStream)
从输入流中读取属性列表(键和元素对)。voidload(Reader reader)
按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。voidloadFromXML(InputStream in)
将指定输入流中由 XML 文档所表示的所有属性加载到此属性表中。Enumeration<?>propertyNames()
返回属性列表中所有键的枚举,如果在主属性列表中未找到同名的键,则包括默认属性列表中不同的键。ObjectsetProperty(String key, String value)
调用 Hashtable 的方法 put。voidstore(OutputStream out, String comments)
以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。voidstore(Writer writer, String comments)
以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。voidstoreToXML(OutputStream os, String comment)
发出一个表示此表中包含的所有属性的 XML 文档。voidstoreToXML(OutputStream os, String comment, String encoding)
使用指定的编码发出一个表示此表中包含的所有属性的 XML 文档。Set<String>stringPropertyNames()
返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。

示例代码:

import java.util.*;
import java.io.*;

public class PropertiesTest
{
public static void main(String[] args)
throws Exception
{
Properties props = new Properties();
// 向Properties中增加属性
props.setProperty("username" , "yeeku");
props.setProperty("password" , "123456");
// 将Properties中的key-value对保存到a.ini文件中
props.store(new FileOutputStream("a.ini")
, "comment line"); //①
// 新建一个Properties对象
Properties props2 = new Properties();
// 向Properties中增加属性
props2.setProperty("gender" , "male");
// 将a.ini文件中的key-value对追加到props2中
props2.load(new FileInputStream("a.ini") ); //②
System.out.println(props2);
}
}


SortedMap接口和TreeMap实现类
类比SortedSet和TreeSet,使用红黑树结构存储,对key进行了排序。
两种排序方式:自然排序和定制排序。


方法摘要Map.Entry<K,V>ceilingEntry(K key)
返回一个键-值映射关系,它与大于等于给定键的最小键关联;如果不存在这样的键,则返回 null。KceilingKey(K key)
返回大于等于给定键的最小键;如果不存在这样的键,则返回 null。voidclear()
从此映射中移除所有映射关系。Objectclone()
返回此 TreeMap 实例的浅表副本。Comparator<? superK>comparator()
返回对此映射中的键进行排序的比较器;如果此映射使用键的自然顺序,则返回 null。booleancontainsKey(Object key)
如果此映射包含指定键的映射关系,则返回 true。booleancontainsValue(Object value)
如果此映射为指定值映射一个或多个键,则返回 true。NavigableSet<K>descendingKeySet()
返回此映射中所包含键的逆序 NavigableSet 视图。NavigableMap<K,V>descendingMap()
返回此映射中所包含映射关系的逆序视图。Set<Map.Entry<K,V>>entrySet()
返回此映射中包含的映射关系的 Set 视图。Map.Entry<K,V>firstEntry()
返回一个与此映射中的最小键关联的键-值映射关系;如果映射为空,则返回 null。KfirstKey()
返回此映射中当前第一个(最低)键。Map.Entry<K,V>floorEntry(K key)
返回一个键-值映射关系,它与小于等于给定键的最大键关联;如果不存在这样的键,则返回 null。KfloorKey(K key)
返回小于等于给定键的最大键;如果不存在这样的键,则返回 null。Vget(Object key)
返回指定键所映射的值,如果对于该键而言,此映射不包含任何映射关系,则返回 null。SortedMap<K,V>headMap(K toKey)
返回此映射的部分视图,其键值严格小于 toKey。NavigableMap<K,V>headMap(K toKey, boolean inclusive)
返回此映射的部分视图,其键小于(或等于,如果 inclusive 为 true)toKey。Map.Entry<K,V>higherEntry(K key)
返回一个键-值映射关系,它与严格大于给定键的最小键关联;如果不存在这样的键,则返回 null。KhigherKey(K key)
返回严格大于给定键的最小键;如果不存在这样的键,则返回 null。Set<K>keySet()
返回此映射包含的键的 Set 视图。Map.Entry<K,V>lastEntry()
返回与此映射中的最大键关联的键-值映射关系;如果映射为空,则返回 null。KlastKey()
返回映射中当前最后一个(最高)键。Map.Entry<K,V>lowerEntry(K key)
返回一个键-值映射关系,它与严格小于给定键的最大键关联;如果不存在这样的键,则返回 null。KlowerKey(K key)
返回严格小于给定键的最大键;如果不存在这样的键,则返回 null。NavigableSet<K>navigableKeySet()
返回此映射中所包含键的 NavigableSet 视图。Map.Entry<K,V>pollFirstEntry()
移除并返回与此映射中的最小键关联的键-值映射关系;如果映射为空,则返回 null。Map.Entry<K,V>pollLastEntry()
移除并返回与此映射中的最大键关联的键-值映射关系;如果映射为空,则返回 null。Vput(K key, V value)
将指定值与此映射中的指定键进行关联。voidputAll(Map<? extends K,? extends V> map)
将指定映射中的所有映射关系复制到此映射中。Vremove(Object key)
如果此 TreeMap 中存在该键的映射关系,则将其删除。intsize()
返回此映射中的键-值映射关系数。NavigableMap<K,V>subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)
返回此映射的部分视图,其键的范围从 fromKey 到 toKey。SortedMap<K,V>subMap(K fromKey, K toKey)
返回此映射的部分视图,其键值的范围从 fromKey(包括)到 toKey(不包括)。SortedMap<K,V>tailMap(K fromKey)
返回此映射的部分视图,其键大于等于 fromKey。NavigableMap<K,V>tailMap(K fromKey, boolean inclusive)
返回此映射的部分视图,其键大于(或等于,如果 inclusive 为 true)fromKey。Collection<V>values()
返回此映射包含的值的 Collection 视图。

示例代码:

import java.util.*;

class R implements Comparable
{
int count;
public R(int count)
{
this.count = count;
}
public String toString()
{
return "R[count:" + count + "]";
}
// 根据count来判断两个对象是否相等。
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj != null && obj.getClass() == R.class)
{
R r = (R)obj;
return r.count == this.count;
}
return false;
}
// 根据count属性值来判断两个对象的大小。
public int compareTo(Object obj)
{
R r = (R)obj;
return count > r.count ? 1 :
count < r.count ? -1 : 0;
}
}
public class TreeMapTest
{
public static void main(String[] args)
{
TreeMap tm = new TreeMap();
tm.put(new R(3) , "轻量级Java EE企业应用实战");
tm.put(new R(-5) , "疯狂Java讲义");
tm.put(new R(9) , "疯狂Android讲义");
System.out.println(tm);
// 返回该TreeMap的第一个Entry对象
System.out.println(tm.firstEntry());
// 返回该TreeMap的最后一个key值
System.out.println(tm.lastKey());
// 返回该TreeMap的比new R(2)大的最小key值。
System.out.println(tm.higherKey(new R(2)));
// 返回该TreeMap的比new R(2)小的最大的key-value对。
System.out.println(tm.lowerEntry(new R(2)));
// 返回该TreeMap的子TreeMap
System.out.println(tm.subMap(new R(-1) , new R(4)));
}
}



WeakHashMap
用法与HashMap一样,区别:HashMap的key保留了对实际对象的强引用,这意味着只要HashMap不被销毁,该HashMap中所有key引用的对象就不会被回收,HashMap也不会删除这些key-value对。但是WeakHashMap的key只保留了对实际对象的弱引用,这意味着如果WeakHashMap对象的key所引用的对象若果没有被其他强引用变量所引用,则这些对象可能会被回收,WeakHashMap也会自动删除这些key-value对。

示例代码:

import java.util.*;

public class WeakHashMapTest
{
public static void main(String[] args)
{
WeakHashMap whm = new WeakHashMap();
// 将WeakHashMap中添加三个key-value对,
// 三个key都是匿名字符串对象(没有其他引用)
whm.put(new String("语文") , new String("良好"));
whm.put(new String("数学") , new String("及格"));
whm.put(new String("英文") , new String("中等"));
//将 WeakHashMap中添加一个key-value对,
// 该key是一个系统缓存的字符串对象。
whm.put("java" , new String("中等")); // ①
// 输出whm对象,将看到4个key-value对。
System.out.println(whm);
// 通知系统立即进行垃圾回收
System.gc();
System.runFinalization();
// 通常情况下,将只看到一个key-value对。
System.out.println(whm);
}
}


IdentityHashMap
实现与HashMap基本相同,但是比较两个key时不同,使用的是严格相等,即key1==key2才会认为两个key相等。而HashMap比较的是equal和hashCode方法。
示例代码:

import java.util.*;

public class IdentityHashMapTest
{
public static void main(String[] args)
{
IdentityHashMap ihm = new IdentityHashMap();
// 下面两行代码将会向IdentityHashMap对象中添加两个key-value对
ihm.put(new String("语文") , 89);
ihm.put(new String("语文") , 78);
// 下面两行代码只会向IdentityHashMap对象中添加一个key-value对
ihm.put("java" , 93);
ihm.put("java" , 98);
System.out.println(ihm);
}
}


EnumMap
key必须是单个枚举值。
示例代码:

import java.util.*;

enum Season
{
SPRING,SUMMER,FALL,WINTER
}
public class EnumMapTest
{
public static void main(String[] args)
{
// 创建EnumMap对象,该EnumMap的所有key都是Season枚举类的枚举值
EnumMap enumMap = new EnumMap(Season.class);
enumMap.put(Season.SUMMER , "夏日炎炎");
enumMap.put(Season.SPRING , "春暖花开");
System.out.println(enumMap);
}
}

HashSet和HashMap的性能
因为HashSet和HashMap、Hashtable都使用hash算法来决定其元素(对HashMap则是key)的存储,因此HashSet、HashMap的hash表包含如下属性:
容量(capacity):hash表中桶的数量。
初始化容量(initial capacity):创建hash表时桶的数量。HashMap和HashSet都允许在构造器中指定初始化容量。
尺寸(size):当前散列表中记录的数量。
负载因子(load factor):负载因子等于“size/capacity”。负载因子为0,表示空的hash表,0.5表示半满的散列表,依此类推。轻负载的散列表具有冲突少、适宜插入与查询的特点(但是使用Iterator迭代元素时会变慢)。
负载极限:0~1的数值,默认是0.75,当hash表中的负载因子达到负载极限时,hash表会自动的成倍的增长容量,rehashing。如果开始就知道要保存的记录数,则可以使用记录数除以负载极限得到最大初始容量,那么以后就不会发生rehashing,提高效率。


============================================
Collections:操作集合的工具类

排序操作:
static  voidreverse(List<?> list) 
          反转指定列表中元素的顺序。static  voidshuffle(List<?> list) 
          使用默认随机源对指定列表进行置换。static  voidsort(List<T> list) 
          根据元素的自然顺序 对指定列表按升序进行排序。static  voidsort(List<T> list, Comparator<? super T> c) 
          根据指定比较器产生的顺序对指定列表进行排序。static  voidswap(List<?> list, int i, int j) 
          在指定列表的指定位置处交换元素。static  voidrotate(List<?> list, int distance) 
          根据指定的距离轮换指定列表中的元素。

示例代码:

import java.util.*;

public class SortTest
{
public static void main(String[] args)
{
ArrayList nums = new ArrayList();
nums.add(2);
nums.add(-5);
nums.add(3);
nums.add(0);
System.out.println(nums); // 输出:[2, -5, 3, 0]
Collections.reverse(nums); // 将List集合元素的次序反转
System.out.println(nums); // 输出:[0, 3, -5, 2]
Collections.sort(nums); // 将List集合元素的按自然顺序排序
System.out.println(nums); // 输出:[-5, 0, 2, 3]
Collections.shuffle(nums); // 将List集合元素的按随机顺序排序
System.out.println(nums); // 每次输出的次序不固定
}
}

查找替换操作:
binarySearch(List<? extends Comparable<? super T>> list, T key) 
      使用二分搜索法搜索指定列表,以获得指定对象。但是必须保证list已处于有序状态max(Collection<? extends T> coll) 
      根据元素的自然顺序,返回给定 collection 的最大元素。max(Collection<? extends T> coll, Comparator<? super T> comp) 
      根据指定比较器产生的顺序,返回给定 collection 的最大元素。min(Collection<? extends T> coll) 
     根据元素的自然顺序 返回给定 collection 的最小元素。min(Collection<? extends T> coll, Comparator<? super T> comp) 
     根据指定比较器产生的顺序,返回给定 collection 的最小元素。fill(List<? super T> list, T obj) 
          使用指定元素替换指定列表中的所有元素。frequency(Collection<?> c, Object o) 
          返回指定 collection 中等于指定对象的元素数。indexOfSubList(List<?> source, List<?> target) 
          返回指定源列表中第一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。lastIndexOfSubList(List<?> source, List<?> target) 
          返回指定源列表中最后一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。replaceAll(List<T> list, T oldVal, T newVal) 
          使用另一个值替换列表中出现的所有某一指定值。singletonMap(K key, V value)
返回一个不可变的映射,它只将指定键映射到指定值。sort(List<T> list, Comparator<? super T> c)
根据指定比较器产生的顺序对指定列表进行排序。

示例代码:

import java.util.*;

public class SearchTest
{
public static void main(String[] args)
{
ArrayList nums = new ArrayList();
nums.add(2);
nums.add(-5);
nums.add(3);
nums.add(0);
System.out.println(nums); // 输出:[2, -5, 3, 0]
System.out.println(Collections.max(nums)); // 输出最大元素,将输出3
System.out.println(Collections.min(nums)); // 输出最小元素,将输出-5
Collections.replaceAll(nums , 0 , 1); // 将nums中的0使用1来代替
System.out.println(nums); // 输出:[2, -5, 3, 1]
// 判断-5在List集合中出现的次数,返回1
System.out.println(Collections.frequency(nums , -5));
Collections.sort(nums); // 对nums集合排序
System.out.println(nums); // 输出:[-5, 1, 2, 3]
//只有排序后的List集合才可用二分法查询,输出3
System.out.println(Collections.binarySearch(nums , 3));
}
}



同步控制:
使用synchronizedXxx()方法将指定集合包装成线程同步的集合:
示例代码:

import java.util.*;

public class SynchronizedTest
{
public static void main(String[] args)
{
// 下面程序创建了四个线程安全的集合对象
Collection c = Collections
.synchronizedCollection(new ArrayList());
List list = Collections.synchronizedList(new ArrayList());
Set s = Collections.synchronizedSet(new HashSet());
Map m = Collections.synchronizedMap(new HashMap());
}
}

设置不可变集合:
static <T> List<T>emptyList() 
          返回空的列表(不可变的)。static <K,V> Map<K,V>emptyMap() 
          返回空的映射(不可变的)。static <T> Set<T>emptySet() 
          返回空的 set(不可变的)。static <T> Set<T>singleton(T o) 
          返回一个只包含指定对象的不可变 set。static <T> List<T>singletonList(T o) 
          返回一个只包含指定对象的不可变列表。static <K,V> Map<K,V>singletonMap(K key, V value) 
          返回一个不可变的映射,它只将指定键映射到指定值。 unmodifiableXxx() 
          返回指定集合的不可修改视图。
示例代码:

import java.util.*;

public class UnmodifiableTest
{
public static void main(String[] args)
{
// 创建一个空的、不可改变的List对象
List unmodifiableList = Collections.emptyList();
// 创建一个只有一个元素,且不可改变的Set对象
Set unmodifiableSet = Collections.singleton("疯狂Java讲义");
// 创建一个普通Map对象
Map scores = new HashMap();
scores.put("语文" , 80);
scores.put("Java" , 82);
// 返回普通Map对象对应的不可变版本
Map unmodifiableMap = Collections.unmodifiableMap(scores);
// 下面任意一行代码都将引发UnsupportedOperationException异常
unmodifiableList.add("测试元素"); //①
unmodifiableSet.add("测试元素"); //②
unmodifiableMap.put("语文" , 90); //③
}
}

古老的接口:Enumeration
不看也罢,既然不用。

集合框架的优点
提供一组可用的集合接口
提供有效的数据结构和算法
可以方便地扩展或改写集合
接口的实现都是可交换的
使设计新 API 的工作降到最少
接口和算法的可重用性












0 0