java集合框架的接口概述


java平台的集合接口所定义的函数是通用的,例如:Collection<E>,但是实现可以选择的支持相关操作,当执行没有被支持的操作时,抛UnsupportedOperationException.异常,有幸的时,java平台的各种集合都实现了相关操作。

附上集合核心接口的层次图:


下面我们来讨论一下集合框架接口:

Collection 集合框架的根接口,在实现中,所有实现中有的允许重复,有的不允许,有的有序,有的无序,java平台没有提供直接的函数实现,而是提供更多的子接口,如  Set and List

Set集合 一个不能包含重复元素的集合.

List 一个有序的集合(有时称为序列)。列表可以包含重复的元素。使用者必须精确的加以控制当在固定的位置插入元素,或查找元素。

Queue

Deque 

Map 将key映射到value的对象。map不能包含重复的key;每个key可以映射到最多一个value

最后两个核心集合接口只是Set和Map的排序版本:

The Collection Interface

Collection接口用于传递需要最大通用性的对象集合。例如,如果我们有一个List集合,我们可以很容易的构建一个Set集合,原因是所有通用的集合实现的构造函数都需要传递一个Collection 参数,我们更可以将这个构造函数视为转化构造函数

List<String> list = new LinkedList<>();
		list.add("weijinhao");
		list.add("zhoufeifei");
		list.add("liuyawei");
		Set<String> set = new TreeSet<>(list);
		for (String string : set) {
			System.out.println(string);
		}

Collection 接口包含了基本操作如:

 int size(), boolean isEmpty(), boolean contains(Object element), boolean add(E element), boolean remove(Object element), and Iterator<E> iterator().

也包含了操作整个集合的方法如:

boolean containsAll(Collection<?> c), boolean addAll(Collection<? extends E> c), boolean removeAll(Collection<?> c), boolean retainAll(Collection<?> c), and void clear()

更有数组操作:

Object[] toArray() and <T> T[] toArray(T[] a)

我们有三种方式遍历集合:集合操作,foreach,iterator

jdk8之后,遍历集合的首选方法时获得一个流,并进行集合操作,通常会配合lambda 一同使用,这样会使代码更加高效简洁。

集合操作的用途很广泛,我打算单独写一张分享给大家,---------------------但是还没有写先占个位置进行插入

集合的遍历:

方法一集合操作(Aggregate Operations)

public static void main(String[] args) {
		List<String> list  = new ArrayList<>();
		list.add("weijinhao");
		list.add("liuyawei");
		list.add("zhoufeifei");
		//此处使用了Lambda表达式
		Stream<String> stream = list.stream();
		stream.forEach((String p) -> {
			System.out.println(p);
			}
		);
	}
有关Lambda表达式的部分在我的专栏里面也有介绍,参见Lambda表达式详解

foreach遍历集合

for (Object o : collection)
    System.out.println(o);

Iterator 遍历集合,也可以进行集合的修改如果你需要的话,我们可以调用集合的实现类中的iterator()函数来获取集合,进行集合的遍历。

Iterator接口如下:

public interface Iterator<E> {
    boolean hasNext();
    E next();
    void remove(); //optional
}

需要注意的时,remove删除的是我们之前调用next函数时返回的那个元素,每次调用next方法只能调用remove方法一次,如果违反此规则则抛出异常。该方法是在迭代时修改集合的唯一安全的方法,别的方法可能会报错。

static void filter(Collection<?> c) {
    for (Iterator<?> it = c.iterator(); it.hasNext(); )
        if (!cond(it.next()))
            it.remove();
}

更要提一点的时,我们看这段代码更是多态的,他可以操作任何类型的集合。

批量操作

containsAll addAll removeAll retainAll clear 

当然他们所实现的功能我们使用基础操作也能实现,但是那并不是高效的。addAll, removeAll, 和 retainAll总是返回true,只要集合的结构发生了改变。我们这里所说的改变不是指集合元素的改变,而是集合大小等。

例如删除一个集合中所有元素为null的
c.removeAll(Collections.singleton(null));

集合转数组的操作

toArray 方法提供了集合转化为数组的桥梁,我们可以不加任何参数的得到一个数组:

Object[] a = c.toArray();

假如我们需要得到固定类型的数组我们可以这样

String[] a = c.toArray(new String[0]);

Set接口

set集合不能存储重复元素,他仅定义了继承下来的方法,并加了更强功能,比如不能重复,值得说的是  equals 和 hashCode方法,他们可以实现set集合的不同实现之间的集合比较,如果他们包含相同的元素,那就是相等的。

提前附图说明一下接口的实现:


hashset 使用hash table 进行元素的存储,是性能最好的,但是他的存储顺序是无序的,TreeSet 使用红黑树景村存储,并排序通过他们的值,他的性能比hashset差,LinkedHashSet 基于hash table 并加上链表,他可以按插入的顺序进行存储,但是他比较低效。

应用场景:

如果你有一个集合包含重复元素,你可以这样做简单的去除重复:

Collection<Type> noDups = new HashSet<Type>(c);

如果你还想保留原始顺序,并去除重复的话可以这样做:

Collection<Type> noDups = new LinkedHashSet<Type>(c);

Set接口的基础操作

set接口的基本操作和collection接口的操作没有什么不同,但是这里我们需要提一点的是强烈建议我们在使用集合的引用时使用集合接口而不是具体的实现,你就会发现多态的艺术。

我们可以将list集合放入到set集合中去:

List<String> list = new ArrayList<>();
		list.add("weijinhao");
		list.add("zhoufeifei");
		list.add("liuyawei");
		HashSet<String> set = new HashSet<>();
		set.add("weijinhao");
		set.addAll(list);
		for (String string : set) {
			System.out.println(string);
		}

这是没有任何问题的。

set的批量操作:

s1.containsAll(s2) — returns true if s2 is a subset of s1. (s2 is a subset of s1 if set s1 contains all of the elements in s2.)
s1.addAll(s2) — transforms s1 into the union of s1 and s2. (The union of two sets is the set containing all of the elements contained in either set.)
s1.retainAll(s2) — transforms s1 into the intersection of s1 and s2. (The intersection of two sets is the set containing only the elements common to both sets.)
s1.removeAll(s2) — transforms s1 into the (asymmetric) set difference of s1 and s2. (For example, the set difference of s1 minus s2 is the set containing all of the elements found in s1 but not in s2.)

现在我们给一个小demo,该模块实现将给定参数分为只出现一次的和出现多次的,但是不希望包含重复元素。

	public static void main(String[] args) {
		Set<String> uniques = new HashSet<>();
		Set<String> dups = new HashSet<>();

		for (int i = 0; i < args.length; i++) {
			if(! uniques.add(args[i])) {
					dups.add(args[i]);
			}
		}
		uniques.removeAll(dups); 
		System.out.println("重复:    " + dups);
		System.out.println("单一: " + uniques);
		
        }

List接口

List集合是一个有序集合,可以包含重复元素,除了继承自Collection的方法外,他还有一些自己的方法,方法如下:

Positional access //— manipulates elements based on their numerical position in the list. This includes methods such as get, set, add, addAll, and remove.
Search //— searches for a specified object in the list and returns its numerical position. Search methods include indexOf and lastIndexOf.
Iteration //— extends Iterator semantics to take advantage of the list's sequential nature. The listIterator methods provide this behavior.
Range-view //— The sublist method performs arbitrary range operations on the list.

java平台包含2个通用目的的List接口实现类,ArrayList拥有者最好的性能,但是LinkedList在默写情况下拥有最好的性能。

集合操作:

基本操作和Collection的差不多,但是需要说明的时remove操作将删除第一次出现位置上的元素,add和addAll将元素添加到list的末尾。

下标访问和查找操作:

基本的下标访问操作有get set add和remove(set和remove操作将返回被修改或删除的位置的旧的元素),

还有其他一些操作如indexOf和lastIndexOf;

addAll操作将插入指定的集合的所有元素在指定的位置,需要注意的是他的插入顺序是我们迭代他们时的顺序。

迭代

增加了一个ListIterator接口,他是Iterator接口的扩展,他允许你在任意方向遍历列表,在迭代过程中修改列表并获取迭代器的当前位置。

ListIterator继承了三个父接口的方法(hasNext,next,remove)并提供了扩展如hasPrevious 和previous(他的功能和hasNext和next类似),这里我们给出一个小的案例来进行倒序遍历:

for (ListIterator<Type> it = list.listIterator(list.size()); it.hasPrevious(); ) {
    Type t = it.previous();
    ...
}

注意该方法的参数,它有两个实现方法,一个是无参的,他返回一个指向开始的ListIterator,另一个返回指定位置开始的ListIterator,我们在这里补充一个概念叫做游标,如果list的长度为n,则这里有n+1个有效的游标位置,游标并不是指向一个特定的元素而是只在两个元素中间,一个将在调用previous返回,一个将在调用next时返回

当然我们还有两个成对的方法,nextIndex 方法很会下一次调用next时返回的下标值,previousIndex返回下一次调用previous时返回的下标值。这两个操作通常用于查找某个元素,报告并记录其下标值,被提供给另外的Iterator以创建从指定位置开始的Iterator。有一点非常好理解,那就是nextIndex 的返回值始终比previousIndex大,但是这又两个特殊的情况(1)当游标在list的开始位置时,调用previousIndex将返回-1(2)游标在list的末尾时调用nextIndex 将返回list.size().下面我们看一个小的应用:

public int indexOf(E e) {
    for (ListIterator<E> it = listIterator(); it.hasNext(); )
        if (e == null ? it.next() == null : e.equals(it.next()))
            return it.previousIndex();
    // Element not found
    return -1;
}

Iterator提供的remove操作删除上一次执行next的那个元素,ListIterator的这个remove操作有两种可能,如果上一次执行的时next操作,则和上例一样,如果执行的是previous则删除previous之前的那个元素,ListInterator接口还提供了两个额外的操作-set和add方法,set方法重写那个元素,add方法可想而知,在游标的前面进行插入,随后你就可以进行previous操作进行获取了。下面贴出一个set的小应用:

public static <E> void replace(List<E> list, E val, E newVal) {
    for (ListIterator<E> it = list.listIterator(); it.hasNext(); )
        if (val == null ? it.next() == null : val.equals(it.next()))
            it.set(newVal);
}

下面是一个add的小案例;

public static <E> 
    void replace(List<E> list, E val, List<? extends E> newVals) {
    for (ListIterator<E> it = list.listIterator(); it.hasNext(); ){
        if (val == null ? it.next() == null : val.equals(it.next())) {
            it.remove();
            for (E e : newVals)
                it.add(e);
        }
    }
}

区域视图(Range-View Operation)

区域视图操作:subList(int fromIndex ,int toIndex) 返回一个List视图范围从fromIndex 到toIndex(包括他);

我们需要注意的时返回的List对象背后是依赖于主List对象的,所以改变前者,也会影响后者。附上代码你可以试着敲一下:

public static <E> List<E> dealHand(List<E> deck, int n) {
    int deckSize = deck.size();
    List<E> handView = deck.subList(deckSize - n, deckSize);
    List<E> hand = new ArrayList<E>(handView);
    handView.clear();
    return hand;
}

我们Collections类中的算法是可以应用于我们的子串的。

尽管子串的操作是十分强大的,但是我们必须要小心其对主串的影响,子串的add和remove是未定义的(就是不知道会发生什么)所以我们要尽量避免长时间使用子串。

List集合算法

Collections有许多算法可以应用于List,使用它你可以很轻松的操作List集合,下面是Collections中方法的介绍:

sort //— sorts a List using a merge sort algorithm, which provides a fast, stable sort. (A stable sort is one that does not reorder equal elements.)
shuffle //— randomly permutes the elements in a List.
reverse //— reverses the order of the elements in a List.
rotate //— rotates all the elements in a List by a specified distance.
swap //— swaps the elements at specified positions in a List.
replaceAll //— replaces all occurrences of one specified value with another.
fill //— overwrites every element in a List with the specified value.
copy //— copies the source List into the destination List.
binarySearch //— searches for an element in an ordered List using the binary search algorithm.
indexOfSubList //— returns the index of the first sublist of one List that is equal to another.
lastIndexOfSubList //— returns the index of the last sublist of one List that is equal to another.
未完待续。。。


猜你喜欢

转载自blog.csdn.net/c1523456/article/details/80153478