1. 栈
栈是一种先进后出的数据结构 浏览器的后退、编辑器的撤销、安卓Activity的返回等都属于栈的功能。
在Java集合中提供有Stack类,这个类是集合类Vector的子类。需要注意的是,关于栈的方法并不是Vector类或者List接口给出的,而是Stack类自己定义的。
接下来介绍栈的三个常用方法。
// 入栈
public E push(E item) {
// 将新元素尾添进栈
addElement(item);
// 返回添加的元素(方便操作)
return item;
}
// 出栈
public synchronized E pop() {
E obj;
// 获取当前栈的大小
int len = size();
// 获取栈顶元素
obj = peek();
// 删除栈顶元素,尾删
removeElementAt(len - 1);
// 返回这个删除的元素
return obj;
}
// 得到栈顶元素
public synchronized E peek() {
int len = size();
// 如果要得到空栈的栈顶元素,抛出异常
if (len == 0)
throw new EmptyStackException();
// 返回栈顶元素
return elementAt(len - 1);
}
使用如下:
import java.util.Stack;
public class Test {
public static void main(String[] args) {
Stack<Character> stack = new Stack<>();
// 元素入栈
stack.push('a');
stack.push('b');
stack.push('c');
stack.push('d');
try {
// 栈空时会抛出 EmptyStackException 异常进入catch块,从而结束打印
while(stack.peek() != null) {
// 出栈栈顶元素,并打印出栈元素
System.out.println(stack.pop());
}
} catch(Exception e) {
System.out.println("栈空");
}
}
}
运行结果,后入先出:
特别注意,对空栈使用peek()时,会抛出一个异常,所以这里遍历栈的操作要放在try-catch块中。
2. 队列
与栈对应,队列是一种先进先出的数据结构,由于这种特性,所以队列被广泛应用于高并发的场景下。
java.util包中提供了一个Queue接口来实现队列操作。并且在Queue接口子类中,有我们集合类的一个老面孔存在——LinkedList类。Queue接口继承关系如下:
从上图可以看出,其实Queue接口也是集合类的一员。
通常在进行队列操作时,我们都直接使用LinkedList进行队列创建。LinkedList中包含的队列操作是Queue接口定义的,方法如下:
// 向队列中添加元素,尾添
public boolean add(E e) {
// 尾添元素
linkLast(e);
return true;
}
// 队首元素出队列
public E poll() {
final Node<E> f = first;
// 队首为空,返回null,不为空返回队首元素
return (f == null) ? null : unlinkFirst(f);
}
// 获取队首元素
public E peek() {
final Node<E> f = first;
// 空队列返回null,否则返回队首元素
return (f == null) ? null : f.item;
}
使用如下:
import java.util.LinkedList;
import java.util.Queue;
public class Test {
public static void main(String[] args) {
// LinkedList是Queue的子类,一般采用其进行队列操作
Queue<Character> queue = new LinkedList<>();
queue.add('a');
queue.add('b');
queue.add('c');
queue.add('d');
// LinkedList的peek()方法在空队列时会返回一个null
while(queue.peek() != null) {
// 出队列队首元素并打印
System.out.println(queue.poll());
}
}
}
运行结果,先入先出:
线程安全的队列+生产消费者模型 = 简化版的卡夫卡。