Queue


Queue是一个很重要的接口。尤其是在并发编程中,比如像BlockingQueue就是继承自Queue接口的。Queue的实现也很多种多样,有最常见的ArrayDeque,LinkedList,这些是按插入顺序排序的。还有具有特殊功能的队列,比如优先级队列PriorityQueue。

先来看看Queue接口的代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21




public interface Queue<E> extends Collection<E> {


//将元素插入队列,总是返回true,如果失败,抛出异常

//比如如果队列的容量不够了,抛出IllegalStateException

boolean add(E e);


//将元素插入队列,如果插入成功返回true,插入失败,返回false

boolean offer(E e);


//返回并移除队列的头部,如果队列为空,抛出NoSuchElementException

E remove();


//返回并移除队列的头部,如果队列为空,返回null

E poll();


//返回队列头部,如果队列为空,抛出NoSuchElementException

E element();


//返回队列的头部,如果队列为空,返回null

E peek();

}




两种系列的操作:

首先要说的是,Queue的操作分为两个系列,一个是在失败时抛出异常,一个是在失败时返回特殊值(null或者false)。对于插入操作,后者是针对有空间限制的队列特有的,其他类型的队列在插入是不会出错的.

操作失败时抛出异常失败时返回特殊值
插入add(e)offer(e)
删除remove(e)poll(e)
获取element(e)peek(e)

不一定是FIFO:

队列一般是按照先入先出(FIFO)的方式排序的,但是也不一定是。比如优先级队列和LIFO队列(栈)。Queue接口只是定义了插入了获取的方式,具体的实现,由底层决定。

最好不要插入null:

队列中最好插入null元素,虽然他的实现允许,比如LinkedList,但是因为poll方法使用null判断队列是否为空,所以在队列中插入null会引起歧义。

PS. 个人觉得,element这个函数名取得简直傻逼。

Deque


Queue是单端的操作。Deque是双端的操作。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87




public interface Deque<E> extends Queue<E> {


//在头部插入元素,如果空间不够,抛出IllegalStateException

void addFirst(E e);


//在尾部追加元素,如果空间不够,抛出IllegalStateException。和add等价

void addLast(E e);


//在头部插入元素,成功返回true,失败返回false

boolean offerFirst(E e);


//在尾部追加元素,成功返回true,失败返回false

boolean offerLast(E e);


//返回并删除头部元素,如果队列为空,抛出NoSuchElementException

E removeFirst();


//返回并删除尾部元素,如果队列为空,抛出NoSuchElementException

E removeLast();


//返回并删除头部元素,如果队列为空,返回null

E pollFirst();


//返回并删除尾部元素,如果队列为空,返回null

E pollLast();


//返回头部元素,如果队列为空,抛出NoSuchElementException。和element等价

E getFirst();


//返回尾部元素,如果队列为空,抛出NoSuchElementException

E getLast();


//返回头部元素,如果队列为空,,返回null

E peekFirst();


//返回尾部元素,如果队列为空,,返回null

E peekLast();


//删除从前往后第一个出现的相等元素

boolean removeFirstOccurrence(Object o);


//删除从后往前第一个出现的相等元素

boolean removeLastOccurrence(Object o);


// *** 队列相关方法 ***


//和addLast等价

boolean add(E e);


//和offerLast等价

boolean offer(E e);


//和removeFirst等价

E remove();


//和pollFirst等价

E poll();


//和getFirst等价

E element();


//和peekFirst等价

E peek();


// *** 栈相关方法 ***


//和addFirst等价

void push(E e);


//和removeFirst等价

E pop();



// *** Collection methods ***


//和removeFirstOccurrence等价

boolean remove(Object o);


boolean contains(Object o);


public int size();


Iterator<E> iterator();


Iterator<E> descendingIterator();


}




两种系列的操作:

和Queue一样,Deque也分为两种风格的操作。

操作失败时抛出异常失败时返回特殊值
插入addFirst(e)/addLast(e)offerFirst(e)/offerLast(e)
删除removeFirst(e)/removeLast(e)pollFirst(e)/pollLast(e)
获取getFirst(e)/getLast(e)peekFirst(e)/peekLast(e)

Queue和Deque等价的方法:

因为Deque是继承自Queue的,而且Deque为了名义,所以函数名都是指定First/Last的,所以Queue中的方法,会和Deque中相应的方法等价:

Queue方法等价的Deque方法
add(e)addLast(e)
offer(e)offerLast(e)
remove()removeFirst()
poll()pollFirst()
element()getFirst()
peek()peekFirst()

规则是:取头插尾

堆栈的方法:

Java集合除了失败的Stack类,并没有定义新的Stack方法,而是把Stack的方法定义在Deque里了。

Stack方法等价的Deque方法等价的Queue方法
push(e)addFirst(e)
pop()removeFirst()remove()
peek()peekFirst()peek()

因为Stack都是针对头部的操作,而Queue是取头插尾,所以只有取的方法有Queue接口对应的方法,push就没有了。

使用Deque来作为Stack:





Deque<Integer> stack = new ArrayDeque<Integer>();

最好不要插入null:

这一点和Queue一样。

PS. Deque继承自Queue,两套方法交杂在一起,Deque可以使用Queue中的方法,但是却很不名义,还是有些乱的。

参考资料