百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

10年程序员浅析JAVA容器与迭代器

toyiye 2024-06-21 12:20 9 浏览 0 评论

java的容器与迭代器是一个老生常谈的话题了。

本文旨在与大家分享一些关于双向链表与迭代器的运用小技巧,并希望本篇文章的内容能够在项目中给你带来帮助。

Stack与LinkedList

Stack是一个LIFO(后进先出)的容器。若要在java中定义一个Stack应该怎么办?

也许你马上会想到,java中对Stack类型的容器提供了源生支持,所以我们使用jdk包中提供的Stack类不就解决问题了吗?

是的,这是很合理的思路。重复造轮子不是java的风格。那么就让我们来看看源生的Stack容器应该如何使用。

先来一睹jdk中的源生Stack容器类:

* @author Jonathan Payne
 * @since JDK1.0
 */
public
class Stack<E> extends Vector<E> {
 /**
 * Creates an empty Stack.
 */
 public Stack() {
 }
 /**
 * Pushes an item onto the top of this stack. This has exactly
 * the same effect as:
 * <blockquote><pre>
 * addElement(item)</pre></blockquote>
 *
 * @param item the item to be pushed onto this stack.
 * @return the <code>item</code> argument.
 * @see java.util.Vector#addElement
 */
 public E push(E item) {
 addElement(item);
 return item;
 }
 .......
 .....
 ...
 .

嗯?等等,Stack继承自Vector?!

糟了!我们仅仅想要一个单纯的LIFO容器,而大名鼎鼎的Vector不仅速度慢还带有一堆我们不需要的“特性”,继续使用源生的Stack显然不是一个好的选择。

这下可棘手了,我们现在要如何实现一个Stack呢?

LinkedList

LinkedList是一个双向链表。关于它,想必不用介绍太多,光看名字就应该能够猜到,你想要的数据结构它应该都能实现。

所以,我们是不是可以通过LinkedList来实现一个自己的Stack类呢?

import java.util.LinkedList;
public class Stack<T> {
 
 // 容器
 private LinkedList<T> lt = new LinkedList<T>();
 
 // 模拟栈的push方法
 public void push(T e) {
 // 压栈
 lt.addLast(e);
 }
 // 模拟栈的pop方法
 public T pop() {
 // 弹栈
 return lt.removeLast();
 }
 // 模拟栈的peek方法
 public T peek() {
 // 取得栈顶元素
 return lt.getLast();
 }
 public boolean isEmpty() {
 return lt.isEmpty();
 }
 public static void main(String[] args) {
 Stack<String> sk = new Stack<String>();
 sk.push("hello");
 sk.push("world");
 System.out.println(sk.pop());
 System.out.println(sk.pop());
 }
}
---------------------
world
hello

太好了。通过LinkedList,我们模拟了一个LIFO数据结构的实现,并且这个类的名字也叫做Stack。

除此之外他还没有Vector的一大堆“特性”。这就是我们需要的单纯的LIFO容器。

迭代器

在上一小节,我们实现了我们自己的LIFO容器。在这一小节,我们想办法让这个LIFO容器变得更“完美”一些。

在Java中,任何容器都属于可迭代对象,且能被foreach所迭代。

显然,我们创造的Stack容器目前还未拥有迭代器特征。由于追求完美和代码洁癖是一个合格的程序员所应该具有的素养,所以接下来让我们对这个Stack进行一点小小的改造。

import java.util.Iterator;
import java.util.LinkedList;
// 继承Iterable接口,使其成为可迭代对象。
public class Stack<T> implements Iterable<T> {
 
 // 容器
 private LinkedList<T> lt = new LinkedList<T>();
 
 // 模拟栈的push方法
 public void push(T e) {
 // 压栈
 lt.addLast(e);
 }
 // 模拟栈的pop方法
 public T pop() {
 // 弹栈
 return lt.removeLast();
 }
 // 模拟栈的peek方法
 public T peek() {
 // 取得栈顶元素
 return lt.getLast();
 }
 public boolean isEmpty() {
 return lt.isEmpty();
 }
 
 // 可迭代对象的标准迭代方法
 @Override
 public Iterator<T> iterator() {
 return lt.iterator();
 }
 public static void main(String[] args) {
 Stack<String> sk = new Stack<String>();
 sk.push("hello");
 sk.push("world");
 // 通过foreach迭代对象(内部通过获取迭代器进行迭代)
 for (String s : sk) {
 System.out.println(s);
 }
 
 // 显示的通过获取Stack迭代器进行迭代
 Iterator<String> skit = sk.iterator();
 while (skit.hasNext()) {
 System.out.println(skit.next());
 }
 
 System.out.println(sk.pop());
 System.out.println(sk.pop());
 }
}
---------------------
hello
world
hello
world
world
hello

现在,Stack是一个标准的LIFO容器了。他就像其他的源生java容器一样,是一个可迭代对象并且能够被foreach所迭代。任何一个Java程序员,都能够像使用其他源生容器一样使用我们的自定义Stack容器了!

反向迭代

好景不长。

正当你在项目中愉快的使用上面的Stack容器解决一个又一个需求时,难题出现了。

业务方提出了一个讨人厌的需求,它需要反向遍历Stack容器。而追求严谨优雅的你,绝对不会允许使用for循环去遍历容器的这种low逼方式出现。

看来只好再对Stack容器的功能进行一些增强了。

import java.util.Iterator;
import java.util.LinkedList;
// 继承Iterable接口,使其成为可迭代对象。
public class Stack<T> implements Iterable<T> {
 
 // 容器
 private LinkedList<T> lt = new LinkedList<T>();
 
 // 模拟栈的push方法
 public void push(T e) {
 // 压栈
 lt.addLast(e);
 }
 // 模拟栈的pop方法
 public T pop() {
 // 弹栈
 return lt.removeLast();
 }
 // 模拟栈的peek方法
 public T peek() {
 // 取得栈顶元素
 return lt.getLast();
 }
 public boolean isEmpty() {
 return lt.isEmpty();
 }
 // 可迭代对象的标准迭代方法
 @Override
 public Iterator<T> iterator() {
 return lt.iterator();
 }
 // 返回一个可迭代对象。重写可迭代对象的iterator方法,返回重写了next()方法的迭代器对象。
 public Iterable<T> reversed() {
 return new Iterable<T>() {
 public Iterator<T> iterator() {
 return new Iterator<T>() {
 private int current = lt.size() - 1;
 
 // 实现hasNext方法
 @Override
 public boolean hasNext() {
 return current >= 0;
 }
 
 // 实现next方法,实现反向迭代
 @Override
 public T next() {
 if (!hasNext()) {
 return null;
 }
 // 先输出结果再--
 T element = lt.get(current--);
 return element;
 }
 
 // 实现remove方法。remove掉最新迭代出的对象。(与源生容器的迭代器实现保持一致)
 @Override
 public void remove() {
 lt.remove(current + 1);
 }
 };
 }
 };
 }
 public static void main(String[] args) {
 Stack<String> sk = new Stack<String>();
 sk.push("hello");
 sk.push("world");
 for (String s : sk) {
 System.out.println(s);
 }
 
 Iterator<String> skit = sk.iterator();
 while (skit.hasNext()) {
 System.out.println(skit.next());
 }
 
 // 通过foreach反向迭代sk
 for (String s : sk.reversed()) {
 System.out.println(s);
 }
 // 显示的调用反向迭代器反向迭代sk
 Iterator<String> reversedSkit = sk.reversed().iterator();
 while (reversedSkit.hasNext()) {
 System.out.println(reversedSkit.next());
 reversedSkit.remove();
 }
 
 if (!sk.isEmpty()) {
 System.out.println(sk.pop());
 System.out.println(sk.pop());
 } else {
 System.out.println("容器为空");
 }
 }
}
---------------------
hello
world
hello
world
world
hello
world
hello
容器为空

现在的Stack容器不仅是一个可迭代对象。通过调用reversed()方法还能支持反向迭代。利用这个容器不仅能解决问题,还能让解决问题的方式变得更优雅。真棒!

总结

大多数情况下,我认为都应该使用LinkedList来实现Stack。同理LinkedList也能够用来实现Queue。不过,需要注意的是通过这种方法实现的容器,依然和java中其他容器一样,默认情况下在并发状态中是不安全的。

并且,对于自己实现的容器,尽量通过迭代器设计模式对其进行功能增强,以符合java Collection的标准,并满足项目中的需求。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码