Java中的集合
来源:互联网 发布:经营杠杆的理解知乎 编辑:程序博客网 时间:2024/06/11 03:33
集合类是Java中一项很有用的工具类,它很像数组但又远远超过数组。它不仅可以存储数量不等的多个对象还可以实现不同的数据结构!
其中集合主要分为Set、List、Map三个体系!
简单说明
Java API中的位置:java.util。
主要分类
本图展示了主要的结构图。集合主要由两个接口派生:Collection
与Map
。
Collection:Set与List的父接口,其继承了Iterable接口(用于迭代,其内部只有一个方法iterator)。
Set:无序集合,内部数据不可重复。查找数据主要依赖于元素本身数据内容。
List:有序集合,内部数据可重复。查找数据主要依赖于元素索引。
Map:具有映射关系(key-value对)的集合,内部数据查找主要依赖于key值,因此key值不可重复,但数据内容可重复。
关于Iterator与Iterable的联系与区别,请自行搜索,我们使用时一般认为集合用Iterator来迭代
另外,关于子接口:
ArrayList:使用数组结构存储,可变长,查询快,增删慢,线程不同步
LinkedList:使用链表数组结构存储,查询慢,增删快
Vector:最先出现的集合,与ArrayList相同,但线程同步,速度慢(弃)
Collection中主要的方法
集合的成员方法从根本上来说就是对数据进行增删改查,但是因为各个集合内部数据结构各异,因此其增删改查的内部实现原理不同。
API中collection的方法
代码示例
这里使用ArrayList来完成Collection的成员方法的演示。
import java.util.*;public class CollectionDemo { public static void print(Object o) { System.out.println(o); } @SuppressWarnings("unchecked") public static void main(String[] args) { ArrayList al1 = new ArrayList(); ArrayList al2 = new ArrayList(); // 1、添加元素 al1.add("Hello"); al1.add("World"); al1.add("Java"); al2.add("Hello"); al2.add("World"); al2.add("Java"); print("al1中存在的元素:" + al1); // 2、删除元素 al1.remove("Java"); print("删除了元素的al1为:" + al1); // 3、判断是否为空 print("al1是否为空?" + al1.isEmpty()); // 4、是否含有指定元素 print("al1是否含有Hello元素?" + al1.contains("Hello")); // 5、元素个数 print("al1中的元素个数:" + al1.size()); // 6、只保留与指定集合的交集 al1.retainAll(al2); print(al1); // 7、移除指定集合也有的全部元素 al1.removeAll(al2); print(al1); // 8、添加指定集合的所有元素 al1.addAll(al2); print(al1); // 9、将集合转换成Object型数组 print(al1.toArray()); // 10、指定对象与之是否相等 print("al1是否和al2相等?" + al1.equals(al2)); // 11、是否包含指定集合的所有元素 print("al1是否包含al2的所有元素:" + al1.containsAll(al2)); // 12、移除所有元素 al1.clear(); print("al1移除所有元素后:" + al1); }}
运行结果
al1中存在的元素:[Hello, World, Java]删除了元素的al1为:[Hello, World]al1是否为空?falseal1是否含有Hello元素?trueal1中的元素个数:2[Hello, World][][Hello, World, Java][Ljava.lang.Object;@15db9742al1是否和al2相等?trueal1是否包含al2的所有元素?trueal1移除所有元素后:[]
说明:代码第七行@SuppressWarnings("unchecked")
是Java中的注解,此处主要是抑制有关”不受检查异常”的警告信息!如果没有此行代码,编译时将会出现以下信息(当然也可以不加此代码并人为忽略此信息)。
$ javac CollectionDemo.java -encoding utf8注: CollectionDemo.java使用了未经检查或不安全的操作。注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
如果你使用的是eclipse,将会跳过编译结果显示,直接生成运行结果。
使用Iterator遍历集合元素
Iterator接口主要有三种方法
代码示例
import java.util.*;public class CollectionDemo { public static void print(Object o) { System.out.println(o); } @SuppressWarnings("unchecked") public static void main(String[] args) { ArrayList al2 = new ArrayList(); al2.add("Hello"); al2.add("World"); al2.add("Java"); // 1、使用foreach遍历集合 for (Object obj : al2) print(obj); print(""); // 2、使用while遍历集合 Iterator it = al2.iterator(); while (it.hasNext()) { String al2Value = (String)it.next(); print(al2Value); if (al2Value.equals("World")) { it.remove(); } } print(""); // 3、使用for遍历集合 for (Iterator it1 = al2.iterator(); it1.hasNext();) print(it1.next()); }}
运行结果
HelloWorldJavaHelloWorldJavaHelloJava
说明:就遍历来讲,本代码中使用了三种方法实现集合的遍历。for循环的遍历所占据的内存随着for循环的结束而消亡,但是while产生的部分内存不会。foreach循环的遍历并不属于Iterator的遍历,我们应该知道其更加简洁,该遍历下的集合元素不可改变!(也不能删除元素)
综上所述,Iterator中存在的方法使得集合在遍历时是没法被修改的(只能删除,不能增加、更改。当然,不推荐在迭代中删除元素),否则将会引发异常(ConcurrentModificationException)。另外,Iterator迭代器采用的是快速失败机制,一旦在迭代中检测到集合被修改就立即引发异常,这样可以避免(多线程)资源共享引发潜在问题。
Set集合
首先我们看以下代码
import java.util.*;public class CollectionDemo { public static void print(Object o) { System.out.println(o); } @SuppressWarnings("unchecked") public static void main(String[] args) { Set hs = new HashSet(); hs.add(new String("Hello")); boolean hsResult = hs.add(new String("Hello")); print(hsResult); print(hs); }}
输出结果
false[Hello]
分析:我们已经知道Set集合中无法存储相同的元素。这是因为Set本身是无序的,我们每次查找元素时,都是直接查找元素内容本身,如果元素存在相同的,那就没法查找了。我们从上方代码中可以知道:
- Set是通过
equals
来区分元素是否相同的,因为此处创建了两个String对象,两者只有值相同,其他不同 - 存放相同元素时,add会返回
false
并存放失败
所以,Set也没比它的父接口Collection多什么东西,只是限制了元素不能相同。
HashSet
看如下代码
import java.util.*;public class CollectionDemo { public static void print(Object o) { System.out.println(o); } @SuppressWarnings("unchecked") public static void main(String[] args) { HashSet hs = new HashSet(); String str1 = new String("Hello1"); String str2 = new String("Hello2"); String str3 = new String("Hello3"); String str4 = new String("Hello4"); hs.add(str1); hs.add(str2); hs.add(str3); hs.add(str4); hs.add(null); print(hs); }}
输出结果:
[null, Hello1, Hello4, Hello2, Hello3]
分析:从此代码中,我们能够得出:
- HashSet不能够保存元素的排列顺序,它每次的输出顺序都不相同,因为它是根据
hash
(哈希,散列)排布的 - 集合的元素可以是
null
- 还有一点:HashSet不是同步的,当我们使用多线程操控HashSet时,需要通过代码维持同步(此处代码没法体现)
另外,我们应该知道在Java中两个对象的hashCode
值相同时,其equals
值不一定是true
;但其equals
值为true
时,其hashCode
一定相等。
因为hash是通过计算对象地址转换成的int值,这个int值面对庞大的数据迟早会相同
hash的价值在于它的速度,当我们想访问HashSet的某个元素时,HashSet会通过hashCode直接计算出元素的地址并提取,此时hashCode起到了”索引”的功能(但我们知道Set是无序的,没有索引)。这和数组的工作非常相似,我们提供索引时,数组能够迅速找到该元素的值。但数组和HashSet相比的缺陷是:元素位置连续,数组长度不可变长。
另外,如果我们想让HashSet能够按照我们想要的方式排序,可以使用LinkedHashSet,它是HashSet的子类,它使用链表来维护元素的次序,维护链表需要损失一部分性能。
TreeSet
TreeSet类实现了SortedSet接口,它能够确保集合元素处于排序状态。因为此集合是有序的,因此其方法必然存在访问指定位置(或指定范围)的元素或集合。下面介绍一些该类特有常见的方法:
代码示例
import java.util.*;public class CollectionDemo { public static void print(Object o) { System.out.println(o); } @SuppressWarnings("unchecked") public static void main(String[] args) { TreeSet ts = new TreeSet(); ts.add(5); ts.add(15); ts.add(12); ts.add(25); print(ts); print(ts.comparator()); print(ts.first()); print(ts.last()); print(ts.lower(14)); print(ts.higher(18)); print(ts.subSet(10, 18)); print(ts.headSet(14)); print(ts.tailSet(14)); }}
输出结果
[5, 12, 15, 25]null5251225[12, 15][5, 12][15, 25]
分析:从代码中可以看出,排序结果是由大小决定的,而不是插入的顺序。
因为TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后按元素升序排列,这就是TreeSet的自然排序。
自然排序
Java提供了一个Comparable接口,该接口定义了int compareTo(Object obj)方法,Java中很多常见的类也已经实现了Comparable接口。比如BigDecimal、BigInteger、Character、Boolean、String、Date、Time(它们都是比较其数值大小、字符的UNICODE值、true>false、时间大小来排序的)。
- 如果我们想将一个以上的对象添加到TreeSet时,该对象必须已经实现了Comparable接口,否则比较时会抛出异常
- 当我们添加对象时,程序会通过红黑树确定其存储位置,因此相同对象(compareTo()返回值为0)无法同时保存
- 添加对象时,程序会自动与已存在的对象比较大小,因此应该尽量保证TreeSet中元素类型相同
- 如果添加了可变元素,那么它将变得不可删除,所以请尽量添加常量元素
定制排序
我们已经知道obj1.compareTo(obj2)方法返回0时代表两个元素值相同,负数代表obj1\
import java.util.*;class M { int age; public M(int age) { this.age = age; } public String toString() { return "M[age:" + age + "]"; }}public class TreeSetDemo { public static void main(String[] args) { TreeSet ts = new TreeSet(new Comparator() { public int compare(Object obj1, Object obj2) { M m1 = (M)obj1; M m2 = (M)obj2; return m1.age > m2.age ? 1 : m1.age < m2.age ? -1 : 0; } }); ts.add(new M(20)); ts.add(new M(-6)); ts.add(new M(0)); System.out.println(ts); }}
运行结果
[M[age:-6], M[age:0], M[age:20]]
分析:由代码可以看出我们在创建TreeSet集合对象的时候同时创建了一个匿名内部类对象,该对象负责ts对象的排序,但是仍然不能向集合中添加不同类型的元素!
List集合
在Collection
的介绍中,我使用的是ArrayList
,它是List的一个典型的子接口,除了上面讲到的内部方法外,本节我还会使用它来记录List的特有方法。
List中特有的部分方法
代码示例
import java.util.*;public class ListDemo { public static void print(Object obj) { System.out.println(obj); } public static void main(String[] args) { List al = new ArrayList(); List al1 = new ArrayList(); //一般添加元素到集合中 al.add("Hello"); al.add("world"); al.add("java"); al.add("Hello"); al1.add("Hello"); al1.add("world"); al1.add("java"); print(al); // 1、添加元素到指定索引 al.add(1, "Test"); print(al); // 2、移除指定索引的元素 al.remove(1); print(al); // 3、添加集合到指定索引处 al.add(1, al1); print(al); // 4、返回指定索引处的元素 print(al.get(2)); // 5、返回指定元素第一次出现的位置 print(al.indexOf(new String("Hello"))); // 6、返回指定元素最后一次出现的位置 print(al.lastIndexOf("Hello")); // 7、更改指定索引处的元素为指定元素 al.set(4, "Test"); print(al); // 8、获取列表的子列表 print(al.subList(1, 3)); }}
输出结果
[Hello, world, java, Hello][Hello, Test, world, java, Hello][Hello, world, java, Hello][Hello, [Hello, world, java], world, java, Hello]world04[Hello, [Hello, world, java], world, java, Test][[Hello, world, java], world]
分析:从代码中我们可以看出,
- List的方法一般是以其索引来操控指定元素的
- 集合加入指定索引处后是以整个集合当做一个元素来处理的
- 代码36行,新建了一个
String对象
“Hello”能够找到原集合中指定元素的位置,说明他是通过equals()
来判断元素是同一个元素的
遍历访问List元素与迭代
在Collection中已经通过三种方式来遍历集合元素,但第三种与第二种遍历其实是相同的。真正的for循环遍历应该是控制它的索引来完成的:
import java.util.*;public class ListDemo { public static void print(Object obj) { System.out.println(obj); } public static void main(String[] args) { List al = new ArrayList(); List al1 = new ArrayList(); al.add("Hello"); al.add("world"); al.add("java"); for (int i = 0; i < al.size() ; i++ ) { print(al.get(i)); } }}
输出结果
Helloworldjava
另外,我们已经知道集合在使用Iterator接口遍历元素时不能更改元素(除了remove())。因此List接口提供了Iterator的子接口ListIterator接口来增加遍历的功能!
代码示例
import java.util.*;public class ListDemo { public static void print(Object obj) { System.out.println(obj); } public static void main(String[] args) { List al = new ArrayList(); List al1 = new ArrayList(); al.add("Hello"); al.add("world"); al.add("java"); ListIterator lit = al.listIterator(); while (lit.hasNext()) { Object obj = lit.next(); print(obj); if (obj == "java") { lit.add("listIterator"); } if (obj == "world") { al.set(0, "test"); } } print(al); print("-------分割符---------"); while (lit.hasPrevious()) { Object obj = lit.previous(); print(obj); } }}
输出结果
Helloworldjava[test, world, java, listIterator]-------分割符---------listIteratorjavaworldtest
说明 :从代码中我们可以看出
- ListIterator能够让集合在遍历时添加、删除或者更改元素
- ListIterator添加了与next()对应的previous()方法,与hasNext()对应的hasPrevious()方法,来反向遍历!
ArrayList
前面一直使用ArrayList来展示集合,因此大部分功能已经讲完。来说一下它本身。
ArrayList与Vector都是基于数组实现的List类,他们的实例化对象使用initialCapacity参数来设置数组的长度(默认长度为10),当长度超过后就会自动增加长度(ArrayList增加50%,Vector增加100%)。另外,我们也可以使用ensureCapacity(int minCapacity)来手动一次性增加长度,还可以使用trimToSize()调整去除两个集合的多余空间。
LinkedList
LinkedList是一个List集合,因此它可以通过索引来访问,同时它也实现了Deque接口,因此它可以当做双端队列使用。因此一般对LinkedList的操作方法类似于对于堆栈的操作!
代码示例
import java.util.*;public class LinkedListDemo { public static void print(Object obj) { System.out.println(obj); } public static void main(String[] args) { LinkedList lld = new LinkedList(); lld.add("Hello"); lld.add("world"); lld.add("java"); print(lld); // 1、将元素元素加入队列的尾部 lld.offer("test1"); print(lld); // 2、将元素元素加入队列的顶部 lld.push("lld"); print(lld); // 3、将元素元素加入队列的顶部 lld.offerFirst("test2"); print(lld); // 4、弹出队列顶部元素(删除) print(lld.pop()); print(lld); // 5、访问但不删除队列顶部的元素 print(lld.peekFirst()); print(lld); // 6、访问但不删除队列底部的元素 print(lld.peekLast()); print(lld); // 7、删除并访问队列最后一个元素 print(lld.pollLast()); print(lld); }}
输出结果
[Hello, world, java][Hello, world, java, test1][lld, Hello, world, java, test1][test2, lld, Hello, world, java, test1]test2[lld, Hello, world, java, test1]lld[lld, Hello, world, java, test1]test1[lld, Hello, world, java, test1]test1[lld, Hello, world, java]
Map集合
简单介绍
因为Map集合保存的是具有映射关系的数据,因此它可以类比成一个函数系统f(x),函数系统中保存着两组数值,一组是变量(Map里面的key),一组是函数值(Map里面的value),我们知道在函数系统中变量x是不可相同的,而函数值f(x)可以相同,Map也是如此。
Map的key集存储形式和Set接口完全相同,不可重复,没有顺序。Map中存在一个keySet()方法返回Map里所有key值组成的Set集。
Map的value非常类似于List:元素与元素之间可以重复,元素根据索引来查找,只是索引由一个整数改为对象。
代码示例
import java.util.*;public class HashMapDemo { public static void print(Object obj) { System.out.println(obj); } @SuppressWarnings("unchecked") public static void main(String[] args) { HashMap hm = new HashMap<>(); HashMap hm1 = new HashMap<>(); // 1、向Map中添加映射关系 hm.put(0, "hello"); hm.put(11, "world"); hm.put(2, "java"); hm.put("test", "java"); hm.put(5, null); print(hm); hm1.put(2, "test"); hm1.put(null, "hashmap"); // 2、查询Map中是否包含指定的key值 print(hm.containsKey(11)); // 3、查询Map中是否包含指定的value值 print(hm.containsValue("hello")); // 4、返回Map中包含key-value对所组成的Set集合 Set s1 = hm.entrySet(); print(s1); // 5、返回对应key值对应的value,如果没有该key,返回null print(hm.get(2)); // 6、查询Map是否为空 print(hm.isEmpty()); // 7、返回所有key值组成的Set集合 print(hm.keySet()); // 8、将指定Map中的键值对添加到本Map中 hm.putAll(hm1); print(hm); // 9、移除指定key值的键值对 hm.remove(11); print(hm); // 10、返回Map的元素个数 print(hm.size()); // 11、清除Map中所有键值对 hm1.clear(); print(hm1); // 12、返回Map中所有values组成的Collection print(hm.values()); }}
运行结果
{0=hello, 2=java, test=java, 5=null, 11=world}truetrue[0=hello, 2=java, test=java, 5=null, 11=world]javafalse[0, 2, test, 5, 11]{0=hello, null=hashmap, 2=test, test=java, 5=null, 11=world}{0=hello, null=hashmap, 2=test, test=java, 5=null}5{}[hello, hashmap, test, java, null]
说明 :
- key或者value都可以是null
- 如果没有泛型规范,key值可以是任意值
- Map提供一个Entry内部类来封装key-value对,计算Entry时只需要考虑它封装的key值就行
- HashMap重写的toString()方法
- 3中通过equals来判定是否包含指定value值
遍历访问Map
我们可以通过key值当做索引访问每一个键值对
for (Object o : hm.keySet()) { print(o + "=" + hm.get(o));}for (Iterator it = hm.keySet().iterator(); it.hasNext();) { Object o = it.next(); print(o + "=" + hm.get(o));}
HashMap与Hashtable
两者都是Map的典型实现类,两者之间的关系可以类比于ArrayList与Vector的关系:
- Hashtable很古老,从JDK1.0就存在了,它包括了两个操控elements的古老方法
- Hashtable是一个线程安全的Map实现,且不允许使用null作为key和value
- HashMap线程不安全,但其效率更高一点
我们应该尽量不使用Hashtable。
如果我们使用自定义类作为key值,那我们重写该类的equals与hashCode时应该保证其判断标准一致:equals输出为true时hashCode也是一样的。
LinkedHashMap实现类就像是Set中的LinkedHashSet一样可以记住元素的存放顺序,其他属性可以类比LinkedHashSet。
SortedMap接口与TreeMap实现类
TreeMap
正如Sort接口->SortedSet子接口->TreeSet实现类,Map->SortedMap子接口->TreeMap实现类。
TreeMap通过红黑树数据结构根据key对节点进行排序,保证所有的key-value处于有序状态。TreeMap有两种排序方式
- 自然排序:所有的key都必须实现了Comparator接口,而且所有key应该是同一个类的对象,否则会抛出ClassCastException异常!
- 定制排序:创建TreeMap时传入一个Comparator对象,该对象负责对TreeMap进行key排序,此时不要求Map的key值实现了Comparator接口。
- 使用自定义的类当做key时必须保证equals(true/false)返回的值与compareTo(0/非0)相同
根据key值访问TreeMap的键值对:
代码实例
import java.util.*;public class TreeMapDemo { public static void print(Object obj) { System.out.println(obj); } @SuppressWarnings("unchecked") public static void main(String[] args) { TreeMap tm = new TreeMap(); tm.put(1, "hello"); tm.put(21, "java"); tm.put(5, "world"); tm.put(2, "test"); // 1、返回该Map中最小key对应的key-value对,如果为空,返回null print(tm.firstEntry()); // 2、返回Map中最小key值 print(tm.firstKey()); // 3、返回该Map中最大key对应的key-value对,如果为空,返回null print(tm.lastEntry()); // 4、返回Map中最大key值 print(tm.lastKey()); // 5、返回大于指定key值的最小key的值 print(tm.higherKey(2)); // 6、返回大于指定key值的最小key值所在的键值对 print(tm.higherEntry(2)); // 7、返回小于指定key值的最大key的值 print(tm.lowerKey(5)); // 8、返回小于指定key值的最大key值所在的键值对 print(tm.lowerEntry(5)); // 9、返回Map的子Map,默认左闭右开 print(tm.subMap(2, 21)); // 10、返回Map的子Map,可以指定左右是否闭 print(tm.subMap(2, true, 21, true)); // 11、返回大于(包括)指定key值的所有key值所在键值对组成的子Map print(tm.tailMap(2)); // 12、返回大于(是否包括取决于第二个参数)指定key值的所有key值所在键值对组成的子Map print(tm.tailMap(2, false)); // 13、返回小于(不包括包括)指定key值的所有key值所在键值对组成的子Map print(tm.headMap(5)); // 14、返回小于(是否包括取决于第二个参数)指定key值的所有key值所在键值对组成的子Map print(tm.headMap(5, true)); }}
运行结果
1=hello121=java2155=world22=test{2=test, 5=world}{2=test, 5=world, 21=java}{2=test, 5=world, 21=java}{5=world, 21=java}{1=hello, 2=test}{1=hello, 2=test, 5=world}
分析 :这和TreeSet的操作真的很像!
工具类Collections
Collections是Java中提供了操作Set、List、Map等集合的工具类,我们可以使用它来对集合元素进行排序、查询、修改等。
针对List集合的用法:
代码实例
import java.util.*;public class ListTest { public static void print(Object obj) { System.out.println(obj); } @SuppressWarnings("unchecked") public static void main(String[] args) { ArrayList al = new ArrayList(); al.add(-2); al.add(0); al.add(2); al.add(5); al.add(10); al.add(-6); print("原排序" + al); // 1、翻转集合元素次序 Collections.reverse(al); print("翻转次序:" + al); // 2、将list集合元素按照随机排序排序 Collections.shuffle(al); print("随机排序:" + al); // 3、将list集合元素按自然排序 Collections.sort(al); print("自然排序:" + al); // 4、将指定 的两个位置的元素相互交换 Collections.swap(al, 1, 4); print("交换1,4位置:" + al); //5、移动后面指定个数的元素到集合前面(+),移动前面指定个数的元素到集合后面(-), Collections.rotate(al, 2); print("移后到前2:" + al); Collections.rotate(al, -3); print("移前到后3:" + al); }}
运行结果:
原排序[-2, 0, 2, 5, 10, -6]翻转次序:[-6, 10, 5, 2, 0, -2]随机排序:[-2, 10, 2, -6, 5, 0]自然排序:[-6, -2, 0, 2, 5, 10]交换1,4位置:[-6, 5, 0, 2, -2, 10]移后到前2:[-2, 10, -6, 5, 0, 2]移前到后3:[5, 0, 2, -2, 10, -6]
说明:sort还有一个方法static void sort(List list,Comparator c)
根据指定的Comparator产生顺序对list集合元素排序。
除了上面的一些操作,Collections还提供了一些查找、替换集合元素的常见方法
代码实例
import java.util.*;public class CollectionsDemo { public static void print(Object obj) { System.out.println(obj); } @SuppressWarnings("unchecked") public static void main(String[] args) { ArrayList al = new ArrayList(); ArrayList al1 = new ArrayList(); al.add(-2); al.add(-3); al.add(0); al.add(12); al.add(-3); al1.add(12); al1.add(-3); print("原集合:" + al); // 1、查找指定元素的索引位置(只适用于List列表) print("列表中0所在的索引:" + Collections.binarySearch(al, 0)); // 2、第一次出现的位置 print(Collections.indexOfSubList(al, al1)); // 3、最后一次出现的位置 print(Collections.lastIndexOfSubList(al, al1)); // 4、查找集合中最大的元素 print("集合中的最大元素:" + Collections.max(al)); // 5、查找集合中最小的元素 print("集合中的最小元素:" + Collections.min(al)); // 6、返回指定元素出现的次数 print("元素-3出现的次数:" + Collections.frequency(al, -3)); // 7、使用新值替换旧值 print("用-1替换-3:" + Collections.replaceAll(al, -3, -1)); // 8、使用指定元素替换List所有元素 Collections.fill(al, "hello"); print("使用hello替换list所有元素:" + al); }}
运行结果
原集合:[-2, -3, 0, 12, -3]列表中0所在的索引:233集合中的最大元素:12集合中的最小元素:-3元素-3出现的次数:2用-1替换-3:true使用hello替换list所有元素:[hello, hello, hello, hello, hello]
同步控制
因为集合框架中的实现类HashSet、TreeSet、ArrayList、ArrayDeque、LinkedList、HashMap、TreeMap都是线程不安全的,所以Java在Collections中引入了同步控制来保证线程安全。
代码实例
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()); }}
说明 :以上代码将会创建对应的线层同步的集合
设置不可变集合
我们一般使用的集合都是可以随时添加元素的,这在某些场合不太安全,因此创建一些不可变的集合至关重要。Collections中提供了三种方法来解决这一问题。
- emptyXxx():返回一个空的、不可变的集合对象
- singletonXxx():返回一个只有包含指定对象(一个元素)的、不可变的对象
- unmodifiableXxx():返回指定集合对象的不可变视图
这三个方法都对List、Set和Map有效。
代码实例
import java.util.*;public class UnmodifiableTest { public static void main(String[] args) { List unmodifiableList = Collections.emptyList(); Set unmodifiableSet = Collections.singleton("hello"); Map hp = new HashMap(); hp.put(1, "hello"); hp.put(2, "java"); Map unmodifiableMap = Collections.unmodifiableMap(hp); unmodifiableList.add("world"); unmodifiableSet.add("world"); unmodifiableMap.put(3, "test"); }}
运行结果
Exception in thread "main" java.lang.UnsupportedOperationException at java.util.AbstractList.add(AbstractList.java:148) at java.util.AbstractList.add(AbstractList.java:108) at UnmodifiableTest.main(UnmodifiableTest.java:10)
说明
我们在编译时不会出现错误,但是运行时将会出现以上错误,这是因为三个集合都是不可变的,如果我们试图向其中加入其他元素,将会报错!
- JAVA中的集合类
- JAVA中的集合类
- JAVA中的集合类
- JAVA中的集合类
- JAVA中的集合类
- JAVA中的集合类 - -
- JAVA中的集合类
- java中的集合类
- Java中的集合类
- Java中的集合
- JAVA中的集合
- java中的集合
- java中的集合排序
- Java中的一些集合
- JAVA中的集合类
- Java中的集合类
- Java中的集合类
- java中的集合SetEntry
- oracle知识点的梳理及复习
- 环境变量错误导致Linux指令不可用
- 程序员的自信和骄傲
- SqlSession(四)
- Single Number III问题及解法
- Java中的集合
- Volley源码分析
- Python Web入门:Django学习与实践之三(models)
- Hibernate 之实体类之间的关系
- 埃氏筛法
- 【转】几种常用的优化方法
- springMVC的请求参数乱码问题
- 合并排序的非递归实现(自底向上设计)
- HDU 6170 / 多校1010 Two strings (dp)