「Java 数据结构全面解读」:从基础到进阶的实战指南

「Java 数据结构全面解读」:从基础到进阶的实战指南

数据结构是程序设计中的核心部分,用于组织和管理数据。Java 提供了丰富的集合框架和工具类,涵盖了常见的数据结构如数组、链表、栈、队列和树等。本文将系统性地介绍这些数据结构的概念、特点以及在 Java 中的实现,并通过代码示例进行演示。


一、数据结构基础概念

数据结构研究的是数据的逻辑结构和物理结构,以及它们之间的关系。

1.1 数据的逻辑结构

数据的逻辑结构反映了数据元素之间的逻辑关系,而与存储位置无关。常见逻辑结构包括:

  • 散列结构:元素之间除了“同属一个集合”外,没有其他关系。
  • 线性结构:元素之间存在一对一的关系,例如数组、链表。
  • 树形结构:元素之间存在一对多的关系,例如二叉树。
  • 图形结构:元素之间存在多对多的关系。

在这里插入图片描述

1.2 数据的物理结构

数据的物理结构描述了数据在计算机内存中的存储方式,主要有:

  • 数组结构:元素在内存中是连续存储的,即元素存储在一整块连续的存储空间中,此时根据索引的查询效率是非常高的,因为可以根据下标索引直接一步到位找到元素位置,如果在数组末尾添加和删除元素效率也非常高。缺点是,如果事先申请足够大的内存空间,可能造成空间浪费,如果事先申请较小的内存空间,可能造成频繁扩容导致元素频繁搬家。另外,在数组中间添加、删除元素操作,就需要移动元素,此时效率也要打折。
  • 链式结构:元素在内存中是不要求连续存储的,但是元素是封装在结点当中的,结点中需要存储元素数据,以及相关结点对象的引用地址。结点与结点之间可以是一对一的关系,也可以一对多的关系,比如:链表、树等。遍历链式结构只能从头遍历,对于较长的链表来说查询效率不高,对于树结构来说,查询效率比链表要高一点,因为每次可以确定一个分支,从而排除其他分支,但是相对于数组来说,还是数组[下标]的方式更快。树的实现方式有很多种,无非就是在添加/删除效率 与 查询效率之间权衡。
  • 索引结构:元素在内存中是不要求连续存储的,但是需要有单独的一个索引表来记录每一个元素的地址,这种结构根据索引的查询效率很高,但是需要额外存储和维护索引表。。
  • 哈希结构:元素的存储位置需要通过其hashCode值来计算,查询效率也很多,但是要考虑和解决好哈希冲突问题。

数据结构和算法是一门完整并且复杂的课程
在这里插入图片描述

二、Java 中常见的数据结构实现

Java 提供了丰富的数据结构支持,包括动态数组、链表、栈、队列和树等。这些数据结构主要通过 java.util 包中的类实现。

2.1 数组

动态数组特点

逻辑结构特点:线性结构

物理结构特点:
  • 申请内存:一次申请一大段连续的空间,一旦申请到了,内存就固定了。
  • 存储特点:所有数据存储在这个连续的空间中,数组中的每一个元素都是一个具体的数据(或对象),所有数据都紧密排布,不能有间隔。
例如:整型数组

在这里插入图片描述

例如:对象数组

在这里插入图片描述

自定义动态数组(拓展)示例代码
package com.test.list;import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;public class MyArrayList<E> implements Iterable<E>{private Object[] all;private int total;public MyArrayList(){all = new Object[10];}public void add(E e) {ensureCapacityEnough();all[total++] = e;}private void ensureCapacityEnough() {if(total >= all.length){all = Arrays.copyOf(all, all.length + (all.length>>1));}}public void insert(int index, E value) {//是否需要扩容ensureCapacityEnough();//添加元素的下标检查addCheckIndex(index);if(total-index > 0) {System.arraycopy(all, index, all, index+1, total-index);}all[index]=value;total++;}private void addCheckIndex(int index) {if(index<0 || index>total){throw new IndexOutOfBoundsException(index+"越界");}}public void delete(E e) {int index = indexOf(e);if(index==-1){throw new NoSuchElementException(e+"不存在");}delete(index);}public void delete(int index) {//删除元素的下标检查checkIndex(index);if(total-index-1 > 0) {System.arraycopy(all, index+1, all, index, total-index-1);}all[--total] = null;}private void checkIndex(int index) {if(index<0 || index>total){throw new IndexOutOfBoundsException(index+"越界");}}public void update(int index, E value) {//更新修改元素的下标检查checkIndex(index);all[index] = value;}public void update(E old, E value) {int index = indexOf(old);if(index!=-1){update(index, value);}}public boolean contains(E e) {return indexOf(e) != -1;}public int indexOf(E e) {int index = -1;if(e==null){for (int i = 0; i < total; i++) {if(e == all[i]){index = i;break;}}}else{for (int i = 0; i < total; i++) {if(e.equals(all[i])){index = i;break;}}}return index;}public E get(int index) {//获取元素的下标检查checkIndex(index);return (E) all[index];}public int size() {return total;}public Iterator<E> iterator() {return new Itr();}private class Itr implements Iterator<E>{private int cursor;@Overridepublic boolean hasNext() {return cursor!=total;}@Overridepublic E next() {return (E) all[cursor++];}@Overridepublic void remove() {MyArrayList.this.delete(--cursor);}}
}
测试类
package com.test.list;import java.util.Iterator;public class TestMyArrayList {public static void main(String[] args) {MyArrayList<String> my = new MyArrayList<>();my.add("hello");my.add("java");my.add("java");my.add("world");my.add(null);my.add(null);my.add("list");my.add("data");System.out.println("元素个数:" + my.size());for (String s : my) {System.out.println(s);}System.out.println("-------------------------");System.out.println("在[1]插入JAVA移动技术栈后:");my.insert(1, "JAVA移动技术栈");System.out.println("元素个数:" + my.size());for (String s : my) {System.out.println(s);}System.out.println("--------------------------");System.out.println("删除[1]位置的元素后:");my.delete(1);System.out.println("元素个数:" + my.size());for (String s : my) {System.out.println(s);}System.out.println("删除null元素后:");my.delete(null);System.out.println("元素个数:" + my.size());for (String s : my) {System.out.println(s);}System.out.println("------------------------------");System.out.println("替换[3]位置的元素为JAVA移动技术栈后:");my.update(3, "JAVA移动技术栈");System.out.println("元素个数:" + my.size());for (String s : my) {System.out.println(s);}System.out.println("替换java为JAVA后:");my.update("java", "JAVA");System.out.println("元素个数:" + my.size());for (String s : my) {System.out.println(s);}System.out.println("------------------------------------");System.out.println("是否包含java:" +my.contains("java"));System.out.println("java的位置:" + my.indexOf("java"));System.out.println("haha的位置:" + my.indexOf("haha"));System.out.println("[0]位置元素是:" + my.get(0));System.out.println("------------------------------------");System.out.println("删除字符串长度>4的元素后:");Iterator<String> iterator = my.iterator();while(iterator.hasNext()) {String next = iterator.next();if(next != null && next.length()>4) {iterator.remove();}}System.out.println("元素个数:" + my.size());for (String string : my) {System.out.println(string);}}
}

2.2 链表

链表特点
  • 数据存储在结点中,结点通过指针连接。
  • 插入和删除效率高,查询效率低。
  • Java 提供了 LinkedList 类实现链表,支持双向链表。

在这里插入图片描述

示例代码
import java.util.LinkedList;public class LinkedListExample {public static void main(String[] args) {LinkedList<String> linkedList = new LinkedList<>();linkedList.add("A");linkedList.add("B");linkedList.add("C");System.out.println(linkedList); // 输出:[A, B, C]}
}

2.3 栈

栈特点

  • 先进后出(FILO)后进先出(LIFO):最后插入的元素最先被移除。
  • 栈只是逻辑结构,其物理结构可以是数组,也可以是链表,即栈结构分为顺序栈和链式栈。
  • 核心类库中的栈结构有 StackLinkedListStack 就是顺序栈,它是 Vector 的子类,而 LinkedList 是链式栈。
核心操作方法
  • peek():查看栈顶元素,不弹出。
  • pop():弹出栈顶元素。
  • push(E e):压入栈顶。
示例代码
import java.util.Stack;public class StackExample {public static void main(String[] args) {Stack<Integer> stack = new Stack<>();stack.push(10);stack.push(20);stack.push(30);System.out.println(stack.pop()); // 输出:30System.out.println(stack.peek()); // 输出:20}
}
自定义单链表(拓展)
package com.test.list;import java.util.Iterator;public class MyOneWayLinkedList<E>  implements Iterable<E>{private Node head;private int total;public void add(E e){Node newNode = new Node(e, null);if(head == null){head = newNode;}else{Node node = head;while(node.next!=null){node = node.next;}node.next = newNode;}total++;}private Node[] findNodes(Object obj){Node[] result = new MyOneWayLinkedList.Node[2];Node node = head;Node find = null;Node beforeFind = null;if(obj == null){while(node != null){if(node.data == null){find = node;break;}beforeFind = node;node = node.next;}}else{while(node != null){if(obj.equals(node.data)){find = node;break;}beforeFind = node;node = node.next;}}result[0] = beforeFind;result[1] = find;return result;}public void delete(Object obj){Node[] nodes = findNodes(obj);Node beforeFind = nodes[0];Node find = nodes[1];if(find != null){if(beforeFind == null){head = find.next;}else {beforeFind.next = find.next;}total--;}}private Node findNode(Object obj){return findNodes(obj)[1];}public boolean contains(Object obj){return findNode(obj) != null;}public void update(E old, E value) {Node find = findNode(old);if(find != null){find.data = value;}}public int size() {return total;}@Overridepublic Iterator<E> iterator() {return new Itr();}private class Itr implements Iterator<E>{private Node node = head;@Overridepublic boolean hasNext() {return node != null;}@Overridepublic E next() {E value = node.data;node = node.next;return value;}}private class Node{E data;Node next;Node(E data, Node next) {this.data = data;this.next = next;}}
}
测试类
package com.test.list;public class TestMyOneWayLinkedList{public static void main(String[] args) {MyOneWayLinkedList<String> my = new MyOneWayLinkedList<>();my.add("hello");my.add("world");my.add(null);my.add(null);my.add("java");my.add("java");System.out.println("一共有:" + my.size());System.out.println("所有元素:");for (String s : my) {System.out.println(s);}System.out.println("-------------------------------------");System.out.println("查找java,null,haha的结果:");System.out.println(my.contains("java"));System.out.println(my.contains(null));System.out.println(my.contains("haha"));System.out.println("-------------------------------------");System.out.println("替换java,null后:");my.update("java","JAVA");my.update(null,"chai");System.out.println("所有元素:");for (String s : my) {System.out.println(s);}System.out.println("-------------------------------------");System.out.println("删除hello,JAVA,null后:");my.delete("hello");my.delete("JAVA");my.delete(null);System.out.println("所有元素:");for (String s : my) {System.out.println(s);}}
}

自定义双链表(拓展)

package com.test.list;import java.util.Iterator;public class MyLinkedList<E> implements Iterable<E>{private Node first;private Node last;private int total;public void add(E e){Node newNode = new Node(last, e, null);if(first == null){first = newNode;}else{last.next = newNode;}last = newNode;total++;}public int size(){return total;}public void delete(Object obj){Node find = findNode(obj);if(find != null){if(find.prev != null){find.prev.next = find.next;}else{first = find.next;}if(find.next != null){find.next.prev = find.prev;}else{last = find.prev;}find.prev = null;find.next = null;find.data = null;total--;}}private Node findNode(Object obj){Node node = first;Node find = null;if(obj == null){while(node != null){if(node.data == null){find = node;break;}node = node.next;}}else{while(node != null){if(obj.equals(node.data)){find = node;break;}node = node.next;}}return find;}public boolean contains(Object obj){return findNode(obj) != null;}public void update(E old, E value){Node find = findNode(old);if(find != null){find.data = value;}}@Overridepublic Iterator<E> iterator() {return new Itr();}private class Itr implements Iterator<E>{private Node node = first;@Overridepublic boolean hasNext() {return node!=null;}@Overridepublic E next() {E value = node.data;node = node.next;return value;}}private class Node{Node prev;E data;Node next;Node(Node prev, E data, Node next) {this.prev = prev;this.data = data;this.next = next;}}
}

自定义双链表测试

package com.test.list;public class TestMyLinkedList {public static void main(String[] args) {MyLinkedList<String> my = new MyLinkedList<>();my.add("hello");my.add("world");my.add(null);my.add(null);my.add("java");my.add("java");System.out.println("一共有:" + my.size());System.out.println("所有元素:");for (String s : my) {System.out.println(s);}System.out.println("-------------------------------------");System.out.println("查找java,null,haha的结果:");System.out.println(my.contains("java"));System.out.println(my.contains(null));System.out.println(my.contains("haha"));System.out.println("-------------------------------------");System.out.println("替换java,null后:");my.update("java","JAVA");my.update(null,"chai");System.out.println("所有元素:");for (String s : my) {System.out.println(s);}System.out.println("-------------------------------------");System.out.println("删除hello,JAVA,null后:");my.delete("hello");my.delete("JAVA");my.delete(null);System.out.println("所有元素:");for (String s : my) {System.out.println(s);}}
}

2.4 队列

队列特点

队列是逻辑结构,其物理结构可以是数组,也可以是链表。队列有普通队列、双端队列、并发队列等等,核心类库中的队列实现类有很多(后面会学到很多),LinkedList 是双端队列的实现类。

Queue 除了基本的 Collection 操作外,队列还提供其他的插入、提取和检查操作。每个方法都存在两种形式:一种抛出异常(操作失败时),另一种返回一个特殊值(nullfalse,具体取决于操作)。Queue 实现通常不允许插入 null 元素,即使在允许 null 的实现中,也不应该将 null 插入到队列中,因为 null 也用作某些方法的特殊返回值,表明队列不包含元素。

抛出异常返回特殊值
插入add(e)offer(e)
移除remove()poll()
检查element()peek()
双端队列(Deque)

Deque,名称 deque 是“double ended queue(双端队列)”的缩写,通常读为“deck”。此接口定义在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(nullfalse,具体取决于操作)。Deque 接口的实现类有 ArrayDequeLinkedList,它们一个底层是使用数组实现,一个使用双向链表实现。

第一个元素(头部)最后一个元素(尾部)
抛出异常特殊值抛出异常特殊值
插入addFirst(e)offerFirst(e)addLast(e)offerLast(e)
移除removeFirst()pollFirst()removeLast()pollLast()
检查getFirst()peekFirst()getLast()peekLast()

此接口扩展了 Queue 接口。在将双端队列用作队列时,将得到 FIFO(先进先出)行为。将元素添加到双端队列的末尾,从双端队列的开头移除元素。从 Queue 接口继承的方法完全等效于 Deque 方法,如下表所示:

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

双端队列也可用作 LIFO(后进先出)堆栈。应优先使用此接口而不是遗留 Stack 类。在将双端队列用作堆栈时,元素被推入双端队列的开头并从双端队列开头弹出。堆栈方法完全等效于 Deque 方法,如下表所示:

堆栈方法等效 **Deque** 方法
push(e)addFirst(e)
pop()removeFirst()
peek()peekFirst()

结论:Deque 接口的实现类既可以用作 FILO 堆栈使用,又可以用作 FIFO 队列使用。

示例代码
import java.util.LinkedList;
import java.util.Queue;public class QueueExample {public static void main(String[] args) {Queue<String> queue = new LinkedList<>();queue.add("A");queue.add("B");queue.add("C");System.out.println(queue.poll()); // 输出:ASystem.out.println(queue.peek()); // 输出:B}
}

2.5 二叉树

二叉树特点
  • 每个节点最多有两个子节点。
  • Java 提供了 TreeMapTreeSet 类实现基于红黑树的有序集合。
示例代码
import java.util.TreeMap;public class TreeMapExample {public static void main(String[] args) {TreeMap<Integer, String> treeMap = new TreeMap<>();treeMap.put(1, "One");treeMap.put(2, "Two");treeMap.put(3, "Three");System.out.println(treeMap); // 输出:{1=One, 2=Two, 3=Three}}
}
普通二叉树:
public class BinaryTree<E>{private TreeNode root; //二叉树的根结点private int total;//结点总个数private class TreeNode{//至少有以下几个部分TreeNode parent;TreeNode left;E data;TreeNode right;public TreeNode(TreeNode parent, TreeNode left, E data, TreeNode right) {this.parent = parent;this.left = left;this.data = data;this.right = right;}}
}

TreeMap红黑树:

public class TreeMap<K,V> {private transient Entry<K,V> root;private transient int size = 0;static final class Entry<K,V> implements Map.Entry<K,V> {K key;V value;Entry<K,V> left;Entry<K,V> right;Entry<K,V> parent;boolean color = BLACK;/*** Make a new cell with given key, value, and parent, and with* {@code null} child links, and BLACK color.*/Entry(K key, V value, Entry<K,V> parent) {this.key = key;this.value = value;this.parent = parent;}}
}

三、总结与建议

Java 提供了对常见数据结构的完整支持,无论是基础的数组、链表,还是复杂的树、队列,都可以通过标准库轻松实现。在实际开发中,应根据场景选择合适的数据结构:

  • 快速随机访问:选择 ArrayList
  • 频繁插入和删除:选择 LinkedList
  • 先进后出:选择 Stack
  • 先进先出:选择 Queue
  • 有序存储:选择 TreeMapTreeSet

通过对这些数据结构的深入理解和灵活运用,可以显著提升程序的性能和可维护性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/502510.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows11安装minikube

主要是按照官网步骤安装&#xff0c;由于是英文&#xff0c;又不是常规安装包的形式&#xff0c;稍微难理解一点&#xff0c;特此记录。 下文仅是对部分步骤做了说明&#xff0c;需要以官网为主&#xff0c;本文为辅。 一、访问minikube官网 https://minikube.sigs.k8s.io/d…

LLM大模型RAG内容安全合规检查

1.了解内容安全合规涉及的范围 我们先回顾一下智能答疑机器人的问答流程。问答流程主要包括用户、智能答疑机器人、知识库、大语言模型这四个主体。 涉及内容安全的关键阶段主要有&#xff1a; 输入阶段&#xff1a;用户发起提问。 输出阶段&#xff1a;机器人返回回答。 知识…

OpenCV计算机视觉 05 图像边缘检测(Sobel算子、Scharr算子、Laplacian算子、Canny边缘检测)

图像边缘检测 边缘检测是图形图像处理、计算机视觉和机器视觉中的一个基本工具&#xff0c;通常用于特征提取和特征检测&#xff0c;旨在检测一张数字图像中有明显变化的边缘或者不连续的区域。 yuancv2.imread(yuan.png) cv2.imshow(yuan,yuan) cv2.waitKey(0) yuan_xcv2.Sob…

【C++】P2550 [AHOI2001] 彩票摇奖

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述输入格式&#xff1a;输出格式&#xff1a;输入输出样例&#xff1a; &#x1f4af;题解思路1. 问题解析 &#x1f4af;我的实现实现逻辑问题分析 &#x1f4af;老…

【调试记录】在CARLA中插入可以播放视频的组件

〇、问题描述 做实验验证的时候&#xff0c;需要在CARLA仿真环境中添加一个可以播放视频的功能&#xff0c;查了很多现有的实验&#xff0c;基本都是插入图像&#xff0c;而对于插入视频&#xff0c;实现的方法就很麻烦了。一开始考虑的是直接用射影变换进行叠加&#xff0c;计…

SQL—Group_Concat函数用法详解

SQL—Group_Concat函数用法详解 在LC遇见的一道很有趣的SQL题&#xff0c;有用到这个函数&#xff0c;就借这道题抛砖引玉&#xff0c;在此讲解一下group_concat函数的用法。&#x1f923; GROUP_CONCAT([DISTINCT] expression [ORDER BY expression] [SEPARATOR separator])…

深入解析 Linux 设备树中的引脚控制(pinctrl)二

在嵌入式开发中,设备树(Device Tree)是描述硬件设备和系统拓扑的重要结构。而在 Linux 内核中,引脚控制(pinctrl)是一个关键的硬件资源管理部分,负责管理和配置设备的引脚(GPIO、I2C、SPI 等接口)功能和状态。设备树通过描述这些引脚的特性,指导 Linux 内核如何正确地…

MySQL(六)MySQL 案例

1. MySQL 案例 1.1. 设计数据库 1、首先根据相关业务需求(主要参考输出输入条件)规划出表的基本结构   2、根据业务规则进行状态字段设计   3、预估相关表的数据量进行容量规划   4、确定主键   5、根据对相关处理语句的分析对数据结构进行相应的变更。   设计表的时…

后台管理系统动态面包屑Breadcrumb组件的实现

在后管理系统开发中&#xff0c;面包屑导航是一个非常常见的功能&#xff0c;通常是根据当前的 url 自动生成面包屑导航菜单&#xff0c;当跳转路由发生变化时&#xff0c;面包屑导航都会随之发生变化&#xff0c;即动态面包屑。 要完成动态面包屑我们需要制作一个动态数组&am…

4.1.2 栈和队列(一)

文章目录 栈的定义栈的基本运算栈的存储结构栈的应用表达式求值 栈和队列的逻辑结构与线性表相同&#xff0c;但是其运算受到限制&#xff0c;统称为运算受限的线性表。 栈&#xff0c; 先进后出 队列&#xff0c;先进先出 栈的定义 栈顶&#xff0c;唯一能操作端 栈底&#xf…

基于氢氧燃料电池的分布式三相电力系统Simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于氢氧燃料电池的分布式三相电力系统Simulink建模与仿真&#xff0c;仿真输出燃料电池中氢氧元素含量变化以及生成的H2O变化情况。 2.系统仿真结果 3.核心程序与模型 版本…

k620老显卡,装cuda.等。

CUDA安装教程&#xff08;超详细&#xff09;-CSDN博客 1.下载支持12.0以上的驱动 NVIDIA RTX Driver Release 550 R550 U12 (553.50) | Windows 11 解压。安装。一路下一步。查看结果 2.下载 cuda CUDA Toolkit Archive | NVIDIA Developer 安装cuda时&#xff0c;第一次…

【数学建模笔记】评价模型-基于熵权法的TOPSIS模型

视频课地址&#xff1a;https://www.bilibili.com/video/BV1eRyVYUEhg 本系列文章和课程一样&#xff0c;只使用Python实现&#xff0c;好久没玩数学建模了 国赛中不能再用TOPSIS&#xff0c;可以做辅助算法。 1. 算法原理 熵权TOPSIS方法是一种结合熵权法和TOPSIS的决策分析…

当今世界如何减少暴戾之气和矛盾纷争

《消暴戾、减纷争》&#xff08;一&#xff09; 暴戾之气常见于陌生人之间、纷争矛盾常见于与陌生人、同事、朋友、家人之间&#xff0c;总之就是一切人际关系、交际 常见案例&#xff1a;路怒症、住户与外卖小哥的纷争&#xff0c;同事、朋友、家人之间的矛盾 小吵还好&#…

【情感】程序人生之情感关系中的平等意识(如何经营一段长期稳定的关系 沸羊羊舔狗自查表)

【情感】程序人生之情感关系中的平等意识&#xff08;如何经营一段长期稳定的关系 & 沸羊羊舔狗自查表&#xff09; 文章目录 1、情感关系中的平等意识2、如何经营一段长期稳定的关系&#xff08;避免左倾 | 敬畏与担当&#xff09;3、沸羊羊/舔狗自查表&#xff08;避免右…

让css设置的更具有合理性

目录 一、合理性设置宽高 二、避免重叠情况&#xff0c;不要只设置最大宽 三、优先使用弹性布局特性 四、单词、数字换行处理 五、其他编码建议 平常写css时&#xff0c;除了遵循一些 顺序、简化、命名上的规范&#xff0c;让css具有合理性也是重要的一环。 最近的需求场…

Go小技巧易错点100例(二十一)

本篇内容&#xff1a; errors.Is方法与两种方式进行error比较 在Go语言中&#xff0c;处理错误&#xff08;error 类型&#xff09;时&#xff0c;errors.Is 和直接使用 操作符进行错误比较&#xff0c;虽然看起来都用于比较错误&#xff0c;但实际上它们有着根本的不同。这主…

【服务器项目部署】✈️将本地项目部署到服务器(二)!

目录 &#x1f44b;前言 &#x1f440;一、功能调整 &#x1f331;二、服务部署 &#x1f49e;️三、代码调整 &#x1f37b;四、章末 &#x1f44b;前言 小伙伴们大家好&#xff0c;上篇文章本地实践了如何将本地项目部署到服务器上&#xff0c;从服务器的选择、服务器环境…

Kafka消息队列

目录 前置内容常用脚本说明和示例描述与定义部分术语说明两种模式点对点模式发布订阅模式 topic主题命令行操作指令生产者Broker消费者 前置内容 队列&#xff1a; 先进先出 应用&#xff1a; 大数据中主要用于离线和实时处理 流程&#xff1a; Flume正常获取数据&#xff0c;…