深入浅出讲解Java集合中的Collection体系

本文将为大家详细讲解Java中的Collection体系,这是我们进行开发时经常用到的知识点,也是大家在学习Java中很重要的一个知识点,更是我们在面试时有可能会问到的问题。

文章较长,干货满满,建议大家收藏慢慢学习。文末有本文重点总结,主页有全系列文章分享。技术类问题,欢迎大家和我们一起交流讨论!

前言

截止到今天,我们《从零开始学Java系列》的文章已经要到一个新的阶段了。在此之前,我们学习了Java里的各种基础知识,包括环境配置、基本语法、分支循环、数组、常用类等。而从今天开始,本系列文章要给大家介绍另一个我们开发时特别常用的知识点--集合!

其实我们之前学习的数组也是集合的一种,但数组的结构比较简单,并且自身也存在一些天生的缺陷,比如数组的长度是不可修改的。然而在很多情况下,我们在开发时并不能直接确定数据的数量,这就导致我们在开发时不能频繁地使用数组。 所以就需要有一种新的存储数据的结构出现,这就是集合类存在的意义。接下来我们就先从整体上来了解一下集合是怎么回事,希望大家能够通过最近的几篇文章,熟练掌握集合的使用和原理。


全文大约 【4400】字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富的案例及配图,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考......

一. 集合简介

1. 数组缺陷

只要是内部能够持有若干个其他Java对象,并对外提供了访问接口的Java对象,都属于集合。

根据之前我们对数组的认知,数组其实也是一种集合,也可以将不同类型的数据存储起来。既然如此,我们为什么还要搞出来一种新的存储结构来进行数据的存储呢?这主要是因为数组自身存在一些缺陷。

我们虽然可以使用数组来保存多个对象,但数组的长度不可变!也就是说,一旦我们在初始化数组时指定了数组的长度,这个数组的长度就不可变了。如果我们要保存数量不断变化的数据,使用数组的效率就会很差。

另外数组也不能保存具有映射关系的数据。有时候我们想根据某个关键字查找到对应的值,数组是做不到的。比如我们想存储学生的成绩信息,”语文—89“,”数学—60“,数组就很难表达出这种一对一的映射关系。

正因如此,数组难以满足我们在开发时的一些需求,所以这就需要有新的存储结构出现,那么集合也就应运而生了。

2. 集合概念

我们可以把集合理解成是一种用于存放对象的容器,可以保存数量不确定的数据,以及保存具有映射关系的数据(也被称为关联数组)。

它就好比是一个锅、一个碗,里面可以存储适当的数据元素,所以集合就是“由若干个确定的数据元素所构成的整体”,负责保存、盛装其他数据,故也被称为容器类。集合的概念在很多编程语言中都有,并不是Java独有的技术。

Java中的集合其实可以理解成是一个”统称“,它实际上主要包括了两种类型的容器,一种是用于存储单个数据元素的Collection集合,属于单列集合,另一种是可以存储键/值对映射关系的Map集合,属于双列集合。

这两个集合接口都是集合的根接口,它们各自又包含了一些子接口或实现类。其中Collection集合又包括3种子类型:List、Set和Queue,而Map集合又包括AbstractMap、SortedMap和HashTable等,如下图所示:

image.png

Java所有的集合类都位于java.util包下,提供了一个表示和操作对象集合的统一构架,内部包含了大量集合接口,以及这些接口的实现类和操作它们的算法。

● 接口:代表了集合的抽象数据类型,例如Collection、List、Set、Map等。集合中定义多个接口,是为了能够以不同的方式操作集合对象;

● 实现类:代表了集合接口的具体实现,例如ArrayList、LinkedList、HashSet、HashMap等。本质上它们都是可重复使用的数据结构;

● 算法:代表了实现集合接口的对象在执行的一些计算功能,例如搜索和排序等。这些算法都是多态的表现,因为相同的方法可以在相似的接口上有着不同的实现。

另外集合类和数组不一样,数组里的元素既可以是基本类型的值,也可以是对象(实际保存的是对象的引用变量),而集合里只能保存对象(实际上是保存的对象引用变量,但通常习惯上我们认为集合里保存的是对象)。

3. 集合特点

从集合的设计实现来看,Java集合中的接口和实现类进行了分离,比如有序表的接口是List,而具体实现类则是ArrayList、LinkedList等。另外集合还支持泛型,使得一个集合只能存放同一种数据类型的元素。

集合包括List、Set、Map等几种不同的实现形式,从功能上来看,它们也有各自的特点:

● List集合: List集合是一个有序的、可重复的集合,各个元素对象之间有指定的顺序,且允许出现重复元素和多个值为null的元素对象。

● Set集合: Set集合是一个不可重复的集合,各个元素对象之间没有指定的顺序,元素不允许出现重复值,且只允许有一个值为null的元素对象。

● Map集合: Map集合是一个无序的,具有唯一key键,但值不唯一的集合,元素允许出现重复值,且元素可以根据索引进行查找。

4. 集合分类

根据上面的描述和集合架构图,我们知道,Java中的集合其实可以分为两大类,若干子类:

● Collection: 属于单列集合,内部包括List、Set和Queue等子类,其中List是一种有序列表的集合,Set是可以保证没有重复元素的集合。

● Map: 属于双列集合,是可以通过键值(key-value)查找的映射表集合,内部包括AbstractMap、SortedMap和HashTable等子类。

5. 核心接口

在上面的描述中,给大家说过,组成集合的架构包括了各种接口,这些常用的接口作用如下:

接口名称 作用
Iterator接口 Iterator迭代器是集合类的输出接口,主要用于遍历输出(即迭代访问)Collection集合中的元素。迭代器是集合接口的父接口,子类实现Collection接口时也必须实现Iterator接口。
Collection接口 Collection是List、Set和Queue的父接口,是存放一组单值的最大接口。所谓的单值,是指集合中的每个元素都是一个对象,但我们一般很少直接使用此接口进行直接操作。
Queue接口 Queue是Java提供的实现队列,有点类似于List。
Dueue接口 Dueue是Queue的子接口,是一个双向队列。
List接口 List是最常用的集合接口。List是有序的集合,允许有相同的元素。我们使用List能够精确地控制每个元素插入的位置,用户能够使用索引(即元素在List中的位置,类似于数组下标)来访问List中的元素,这与数组类似。
Set接口 Set中不能包含重复的元素。
Map接口 Map是存放键值对的接口,该接口中的每个元素都是成对出现,以key-value的形式保存。

6. 常用实现类

我们在开发时常用List、Set和Map这3种集合接口,而常用的集合实现类则是ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等。

类名称 作用
ArrayList ArrayList是基于可变数组实现的List,优点是可以进行快速地随机访问,查询效率高,但数据的增删改操作速度较慢。
LinkedList LinkedList是基于链表实现的List,对顺序访问进行了优化,数据的增删改操作效率较高,但随机访问的速度相对较慢。
HashSet HashSet是基于HashMap实现的Set,底层使用HashMap来保存所有的数据元素,内部实现比较简单,优化了査询速度。
TreeSet TreeSet是一个有序的Set子类,我们可以从中提取一个有序序列。
HashMap HashMap是根据哈希算法来进行键值对存取的Map集合,属于双列集合。
TreeMap TreeMap是可以对键对象进行排序的Map集合。

7. 过时API

集合作为Java里特别常用和重要的API,可以说几乎每个Java项目都有集合的身影。但是集合结构从JDK 1.0开始就被设计出来,其设计实现非常久远,中间经历了几次大的修改。这就像一个庞大的机器经历了几十年的修修补补,虽然性能依然强悍,但也存在一些不适合继续使用的过时API,比如:

● Vector: 一种线程安全的List实现类,不推荐使用;

● Stack: 基于Vector实现的LIFO的栈,不推荐使用;

● Hashtable: 一种线程安全的Map实现,不推荐使用;

● Enumeration: 已被Iterator取代,不推荐使用。

以上这些API都已被遗弃,开发时请大家尽量不要再使用。另外现在我们只是简单地认识一下集合中的接口和个别实现类,后面再详细地给大家进行进行介绍,先不要着急哦。

二. Collection接口

在上面的内容中,说过,集合主要有两大接口,即Collection和Map,而Collection接口其实又是List和Set的父接口。在开始详细学习List和Set集合类之前,我们先来搞清楚Collection是怎么回事。

1. 简介

Collection接口是List、Set和Queue的父接口,在开发时我们不会直接使用该接口,而是会使用该接口的某个具体实现子类。Collection接口里定义了List/Set/Queue的一些通用方法,这些方法可以操作List、Set和Queue集合,实现对集合基本的添加、删除、判断等操作。

image.png

2. 方法

下面是Collection接口中定义的一些常用方法,我们可以先来了解一下这些常用方法的含义,以后开发时这些方法都很常用。

方法名称 说明
boolean add(E e) 向集合中添加一个元素,添加成功后返回true,E是指数据元素的数据类型。
boolean addAll(Collection c) 向集合中添加另一个集合c的所有元素,添加成功后返回true。
void clear() 清除集合中的所有元素,将集合长度变为0。
boolean contains(Object o) 判断集合是否存在指定的元素。
boolean containsAll(Collection c) 判断一个集合是否包含另一个集合c的所有元素。
boolean isEmpty() 判断集合是否为空。
Iterator iterator() 返回一个Iterator对象,用于遍历集合中的元素。
boolean remove(Object o) 从集合中删除一个指定的元素,当集合中包含一个或多个元素o时,该方法只会删除第一个符合条件的元素,删除成功后返回true。
boolean removeAll(Collection c) 从集合中删除所有在集合c中出现的元素,删除成功后返回true。
boolean retainAll(Collection c) 从集合中删除所有不在集合c里的元素,删除成功后返回true。
int size() 返回集合的元素个数。
Object[] toArray() 将集合转换成一个数组,所有的集合元素会变成对应的数组元素。

因为Collection是一个接口,所以我们不能对其直接进行实例化操作,上述表格中的这些方法,我们需要先创建出某个具体的实现类对象进行调用,比如调用ArrayList对象的相关方法。

三. Iterator迭代器

1. 简介

我们可以使用Iterator迭代器对集合进行遍历,Iterator迭代器是集合类的输出接口,主要用于进行遍历输出(即迭代访问)Collection集合中的每个元素。迭代器是集合接口的父接口,子类实现Collection接口时也必须实现Iterator接口。不同的List对象调用iterator()方法时,会返回不同实现的Iterator对象,该Iterator对象对集合总是具有最高的访问效率。

2. 迭代原理

所谓的迭代,其实是一个重复反馈过程的活动,也就是一遍又一遍地执行相似的任务,其目的通常是为了逼近所需的目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果又会作为下一次迭代的初始值。迭代器的工作原理如下图所示:

3. 基本使用

Iterator迭代器的使用其实也很简单,主要是有两个常用方法,如下所示:

● boolean hasNext(): 该方法用于判断集合中是否还有下一个元素;

● E next(): 该方法用于返回集合的下一个元素。

import java.util.Iterator;
import java.util.List;

public class Demo02 {
	public static void main(String[] args) {
		//List遍历方式一,普通for循环:
		List list = List.of("java", "大数据", "壹壹哥");
		for(int i=0;i
			System.out.println("遍历方式一,值="+list.get(i));
		}
		
		//List遍历方式二,迭代器:
		Iterator it = list.iterator();
        while(it.hasNext()){
        	//取出下一个值
            String value = it.next();
            System.out.println("遍历方式二,值="+value);
        }

        //List遍历方式三,增强for循环:内部会自动使用Iterator
		for(String item:list) {
			System.out.println("遍历方式三,item="+item);
		}
	}
}

4. 潜在问题

我们在使用迭代器时,有可能会出现如下若干问题需要我们注意:

● 迭代器迭代完成后,迭代器的位置在最后一位,所以迭代器只能迭代一次;

● 迭代器在迭代时,不要多次调用next()方法,否则可能会出现NoSuchElementException异常;

● 迭代器在迭代时,不能向集合中添加或删除元素,否则会出现ConcurrentModificationException异常。


四. 结语

至此,就把集合的基本情况给大家介绍完了,请大家梳理记忆集合类之间的这些关系。

我们在面试时,经常会有面试官问我们Java中有哪些集合类,它们是什么关系和区别,其实考察的就是今天的内容。那么今天的重点内容,给大家总结如下:

● Java集合类定义在java.util包中;

● Java集合的接口和实现类进行了分离,支持泛型;

● Java集合分为Collection和Map两大类,具体又分为List、Set、Queue和Map等子类;

● Java集合使用Iterator遍历集合,我们在开发时尽量不要使用遗留接口。


以上就是本文的全部内容啦,有不明白的地方欢迎大家一起交流讨论!

更多Java技术类干货,可以戳我主页

Java系列免费学习视频,B站搜索千锋教育即可观看

视频传送门:千锋教育B站主页

本文转载于网络 如有侵权请联系删除

相关文章

  • 【题解】乘法逆元2

    题目描述给定n个正整数,求它们在模p意义下的乘法逆元。由于输出太多不好,所以将会给定常数k,你要输出的答案为:答案对p取模。输入格式第一行三个正整数n,p,k,意义如题目描述。 第二行n个正整数aia_iai​,是你要求逆元的数。输出格式输出一行一个整数,表示答案。输入输出样例输入#1623342 142857复制输出#191复制说明/提示对于30%的数据,对于100%数据,保证p为质数。题目分析将题目要求的式子展开我们进行通分,可得同余连续性对于除法来说是不成立的,可以利用逆元,将除法转化为乘法。,x为b的逆元。计算a/ba/ba/b这样的除法算式,可以先把a,b各自对模数p取模,再计算作为最终的结果。利用费马小定理求逆元:代码实现#include<iostream> #include<cstdio> usingnamespacestd; constintN=5e6+5; typedeflonglongll; intn,p,k; llmypow(llx,lln,intM){//快速幂 if(n==0)return1%M; lltmp=mypow(x,n/2

  • 对 wrk Latency Distribution 不准确的分析

    题图:PhotobySnapwirefromPexels wrk是一个非常棒的HTTP压力测试工具,构建在Redis、NGINX、Node.js和LuaJIT这几个开源项目的基础之上,充分利用了他们在事件驱动、HTTP解析、高性能和灵活性方面的优点,并且可以自己写Lua脚本来生成测试请求。 虽然wrk没有测试案例,并且作者大概一年现身一次来合并代码,但这些并不妨碍我们把wrk作为性能测试和fuzz测试的首选工具。如果你还在使用多线程的ab,那么非常值得尝试下wrk。下面是wrk结果中的延时分布统计部分:LatencyDistribution 50%1.20ms 75%595.78ms 90%899.11ms 99%1.00s复制这个示例是指,50%的请求在1.2ms内完成,90%的请求在899ms内完成,99%的请求在1s内完成。我们在使用wrk压力测试自己产品的时候,发现wrk统计的延时结果中,大部分请求都是几毫秒内完成,但有一小部分请求的延时会超过100毫秒。对于用OpenResty构建的系统,出现这么大的延时是不太科学的事情。虽然这个问题最终解决方法非常简单,但具体的分析和定位有

  • Ognl 语法基础教程

    本文将力求用最简单的语言和实例,介绍一下OGNL的语法规则,文章主要内容参考自官方文档http://commons.apache.org/proper/commons-ognl/language-guide.html本篇主要是语法介绍篇,实战放在一下篇因为本篇文章将是后quick-fix2.0版本支持ognl的前导篇,先提前放出<!--more-->1.前言ognl,全称ObjectGraphicNavigationLanguage(对象图导航语言),根据约定的一些简单的规则,组装一个利于阅读、可执行的表达式语句如下面是一个典型的表达式"name".toCharArray()[0].numericValue.toString()复制即便完全不懂ognl,单纯的以java的基础知识就可以看懂,而这就是ognl的魅力所在(学习一点点东西,就可以马上入手)2.对象定位说明,这一小节的内容为我个人为了方便理解而分类的,并不官方 我们知道在java中,一切都是对象,所以我们的ognl表达式必然是着手于某一个对象的,通常在ognl中,可以将待执行目标对象划分为三类简

  • 最全 14 张 Python 思维导图:构建程的核心知识体系!

    本文主要涵盖了Python编程的核心知识(暂不包括标准库及第三方库)。按顺序依次展示了以下内容的一系列思维导图:基础知识,数据类型(数字,字符串,列表,元组,字典,集合),条件&循环,文件对象,错误&异常,函数,模块,面向对象编程;结合这些思维导图主要参考的资料,分享一下我的学习体验,一方面可供初学者参考,另一方面,也便于大家结合思维导图深入学习、理解、思考;思维导图默认阅读顺序:从右→左,顺时针方向。思维导图软件:XMind总览14张思维导图第1张图基础知识图一包括了基本规则、Python语言特点、计算机语言、如何运行Python、变量赋值五个方面,辅助你快速掌握Python编程的基底知识。第2张图基础知识图二包含了模块结构、布局、IO编程流程、标识符、Python对象、内存管理、动态类型六大模块,两张基础知识导图可以帮助你区域化了解Python的组成部分及基本操作。第3张图学习Python少不了对数据的了解,这张图整理了数据类型的分类、作用、空值、标准数据、if语句等等模块。第4张图这张图整理了序列的有序排列、标准操作符与序列类型操作符的重点知识,以及可操作性的BI

  • 本机web开发环境的搭建--nginx篇

    之前写过两篇nginx安装和配置的相关文章:a)、Linux下的Nginx安装(开机自启动)b)、nginx的配置笔记我在工作中配置nginx一般用于网页游戏的开发和网站的开发、调试…而这篇主要针对的是初接触nginx/web初学者,在公司内部也主要是针对新入职的同事,统一了nginx的相关安装环境(例如:d:\nginx-1.3.11)第一步:下载与安装复制zip文件到D盘,并选择解压到当前文件夹。(通过百度网盘下载zip文件>>)进入解压后的文件目录D:\nginx-1.3.11。第二步:使nginx作为服务随并随系统自动启动下载zip文件,并解压到d:\nginx-1.3.11(通过百度网盘下载zip文件>>)进入D:\nginx-1.3.11\nginx_installSrv目录,双击运行“installService.bat”如有360杀毒软件,提醒注册表需要解锁,允许通过即可。至此Nginx服务便随系统自动启动了。复制D:\nginx-1.3.11\nginx_installSrv目录下的三个bat文件:restart-nginx.bat、start

  • [x86][kvm]avx512指令相关

    前言:前文《[x86][linux]AVX512指令引起的进程crash》中,介绍了一次因为avx512指令导致的进程crash。本文记录一下avx指令导致的计算的性能差异,以及内核、虚拟化对avx512的支持。分析:1,linux-4.14avx512lscpu|grepFlags可以看到kernel对avx的支持情况。avx,avx2,avx512bw,avx512c,avx512dq,avx512f,avx512vl2,linux-4.4avx512在linux-4.4上同样执行lscpu|grepFlags,发现只有avx,avx2,avx512cd,avx512f。在https://www.kernel.org上查看最新的4.4longterm的changelog,并没有支持。3,KVM支持情况目前linux-4.14上,已经支持了avx,avx2,avx512bw,avx512c,avx512dq,avx512f,avx512vl。Guest里面是否支持取决于Guest的kernel版本。4,glibc对avx的支持在ubuntu1604的版本中,使用glibc2-23,不

  • Go 语言反射和范型在 API 服务中的应用

    Goreflect为何需要使用reflect获取:减少重复代码1.API接口中抽取参数的逻辑大量重复  API接口自然是要获取传过来的数据,不同接口要获取的数据自然也不一样,如果不做特殊处理,必然是每个接口都有一堆功能重复的从request里获取参数的代码。2.API框架提供的抽取参数的方式并不满足需求  当然API框架会提供这些功能,不过有些情况不能满足需求,比如gin-gonic,提供了将将request转为对应结构体的函数,但存在两个问题,第一个问题是参数区分大小写,我觉得应该实现大小写的通配,这样健壮性更高;第二是结构体直接对应数据库表结构,部分数据是不应该从接口请求中读取的,比如创建时间和删除标志,全转换的方式就很有问题。   不过也有可能是因为我对gin不熟悉,不知道更好的用法,才自己造轮子,如果大家有更简洁漂亮的写法,请不吝赐教。3.Golang强类型语言的限制  Go语言是强类型语言,函数间传递参数或者返回值,必须有特定的类型,如果要实现这种范类型的处理相对Python等弱类型的语言要困难一些。   Python对于struct参数没有严格的限制,传什么内容都行,Gol

  • 假期不想看外出看展?如果是福特GT40MR互动展呢~

    得益于VR/AR/MR很好的可视化展示能力,当前的VR/AR技术早已渗透到了汽车全产业链的每一环节,包括设计、研发、制造、培训、销售等。而为了能够让大众更好了解福特GT系列超级跑车的历史和内部运作系统,彼得森汽车博物馆也赶上这趟VR/AR/MR的顺风车,与福特、HoloLens应用开发商Zengalt联手合作,推出了一个MR互动展览“美国超级跑车展”。本次MR互动展览主要展出的是一款1967年的福特GT40MarkIII,这是一款在20世纪60年代赢得过多次勒芒24小时耐力赛的著名高性能赛车。而作为福特GT40MarkIII的接班人,2017年福特GT40也是本次展览的主角之一。为了让观众更生动直观地观察这两辆车,彼得森汽车博物馆特意为观众准备了HoloLens眼镜。观众带上HoloLens眼镜后,眼前会出现一幅全息图像。通过该图像,观众可以清楚地了解到这两款车的历史以及共同点,并且可顺着时间线探索GT40的赛车血统。关于开设MR互动展览的目的,彼得森汽车博物馆表示,通过MR技术将真实与虚拟融合在一起,并利用空间音频让观众感受汽车引擎、以及轮胎划过地面的摩擦声,加深观众对于汽车的印象。

  • Windows 下使用Git 客户端访问 GitLab 源代码管理库

    Windows下使用Git客户端访问GitLab源代码管理库在Windows下使用Git客户端访问GitLab源代码资源:第一步:客户端下载地址: http://download.csdn.net/detail/accesine960/9913786第二步:安装第三步:打开Bash客户端        运行程序: c:\ProgramFiles\Git\git-bash.exe第四步:生成ssh密钥        在打开的命令行窗口中运行命令:ssh-keygen第五步:拷贝公有密钥文件内容:  运行命令: cat~/.ssh/id_rsa.pub拷贝公有密钥内容。第六步:访问GitLab服务器的地址:http://您的服务器地址/profile/keys完成添加。第七步: gitclone下载源代码测试:

  • 工作线程数究竟要设置为多少 | 架构师之路

    一、需求缘起Web-Server通常有个配置,最大工作线程数,后端服务一般也有个配置,工作线程池的线程数量,这个线程数的配置不同的业务架构师有不同的经验值,有些业务设置为CPU核数的2倍,有些业务设置为CPU核数的8倍,有些业务设置为CPU核数的32倍。“工作线程数”的设置依据是什么,到底设置为多少能够最大化CPU性能,是本文要讨论的问题。二、共性认知在进行进一步深入讨论之前,先以提问的方式就一些共性认知达成一致。问:工作线程数是不是设置的越大越好?答:肯定不是的服务器CPU核数有限,能够同时并发的线程数有限,单核CPU设置10000个工作线程没有意义线程切换是有开销的,如果线程切换过于频繁,反而会使性能降低问:调用sleep()函数的时候,线程是否一直占用CPU?答:不占用,等待时会把CPU让出来,给其他需要CPU资源的线程使用。不止sleep()函数,在进行一些阻塞调用时,例如网络编程中的:阻塞accept(),等待客户端连接阻塞recv(),等待下游回包都不占用CPU资源。问:单核CPU,设置多线程有意义么,是否能提高并发性能?答:即使是单核,使用多线程也是有意义的,大多数情况也

  • 腾讯云专线接入应用场景

    您可通过如下视频了解专线接入的应用场景。 专线接入可应用于如下场景: 数据迁移、备份、恢复专线接入为您提供本地数据中心与云上网络之间快速可靠的连接,可支持的带宽高达100Gbps,非常适用于数据迁移、灾难恢复和其他高可用性策略等方案。 灵活扩展本地数据中心计算能力专线接入是可预测的、高吞吐量的可靠连接,本地数据中心可利用云上弹性计算能力,灵活扩展云下数据中心应用层能力,无需牺牲网络性能便可享受公有云的规模和经济效益。

  • 关于代码质量退化的思考

    一个软件项目从探索阶段到发展方向明确阶段,会经历从简单到复杂的一个过程,需求的不断叠加,会让系统越来越庞大,功能繁多,公司业务的扩展也让软件系统的生命周期变的更长。在业务变复杂软的过程中,各种原因的驱使,代码质量会退化,维护和开发新功能的成本也会相应的变高,推倒重新开发的成本也是高的吓人。 代码质量退化的步骤 大多情况下编码设计质量最高的时候是根据第一版需求进行编码实现的时候,但只要需求一变更,就会打乱原来的编码设计,软件质量也就会越来越差。或者就没有了设计。 到了项目中期,有新的功能或者bug的修复,老板就给我了一天时间,让我写好处理代码?逾期是要被骂的;这个没用的功能,做了也没人用,随便写吧,早点结束,早去干别的;我手上现在这么多活,你又插进来个新功能,我只能乱搞了,团队内人员水平的不同写的代码更是天差地别,等等,这都是我们实际工作中会遇到的问题。责任心让我们也会想先这样写,以后再重构,一般以后重构表示永远不会重构。 上面说的这些都会让我们增加糟糕的代码,混乱的业务逻辑分布在我们系统的各个地方,部门人员变动,新的员工更不可能理解那些杂乱无章的东西,再接着推糟糕的代码,想要理清楚一

  • 高效IO解决方案-Mmap「给你想要的快」

    随着技术的不断进步,计算机的速度越来越快。但是磁盘IO速度往往让欲哭无泪,和内存中的读取速度有着指数级的差距;然而由于互联网的普及,网民数量不断增加,对系统的性能带来了巨大的挑战,系统性能往往是无数技术人不断追求的方向。 CPU,内存,IO三者之间速度差异很大。对于高并发,低延迟的系统来说,磁盘IO往往最先成为系统的瓶颈;为了减少其影响,往往会引入缓存来提升性能。但是由于内存空间有限,往往只能保存部分数据;并且数据需要持久化,所以磁盘IO仍然不可避免。 无论是从HDD(机械硬盘)到SSD(固态硬盘)的硬件提升;还是从BIO(阻塞IO)到NIO(非阻塞IO)的软件上的提升;都使得磁盘IO效率得到了很大的提升,但是相比内存读取速度仍然有着接近巨大的差距。今天笔者将介绍一种更加高效的IO解决方案Mmap(内存映射文件,memorymappedfile) 1.用户态和内核态 为了安全,操作系统将虚拟内存划分为两个模块,即用户态和内核态。它们之间是相互隔离的,即使用户程序崩溃了也不会影响系统的运行。 用户态和内核态包含很多复杂的概念,在此不做过多介绍。简单来说,用户态是用户程序代码运行的地方,

  • 几何

    基础 直线方程 知道两个点,\((x_1,y_1),(x_2,y_2)\),确定一条直线。\(Ax+By+C=0\) \((y_1-y_2)\timesx+(x_2-x_1)\timesy+(x_1\timesy_2-x_2\timesy_1)=0\) 对角线数量 P2181对角线-洛谷|计算机科学教育新生态(luogu.com.cn) n个顶点的凸多边形,它的任何三条对角线都不会交于一点,(顶点不算交点).请求出图形中对角线交点的个数. 分析:一个交点确定两条对角线,确定四个点,则ans=C(4,n) 长方形最多的个数 N条水平线与M条竖直线构成的网格中,放K枚石子,每个石子都只能放在网格的交叉点上。最多可以找到多少四边平行于坐标轴的长方形且它的四个角上都恰好放着一枚石子。 结论:石子摆成接近矩形,只有一个缺口时最优。枚举矩形宽和长,取最大值。 P2180摆石子-洛谷|计算机科学教育新生态(luogu.com.cn) 求三角形的面积 三个互不相同的点(x1,y1),(x2,y2),(x3,y3),求面积。 doublea=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y

  • sharding-jdbc使用笔记

    核心概念: 1.逻辑表:水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例,根据主键尾数拆分为10张表,分别是t_order_0到t_order_9,他们的逻辑表名为t_order 2.真实表:在分片的数据库中真实存在的物理表。即上个示例中的t_order_0到t_order_9。 3.数据节点:数据分片的最小单元。由数据源名称和数据表组成,例:ds_0.t_order_0 4.绑定表:指分片规则一致的主表和子表。例如:t_order表和t_order_item表,均按照order_id分片,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。 5.广播表:指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表。   分片算法:精确分片算法、范围分片算法、复合分片算法、Hint分片算法 SQLHinit: 对于分片字段非SQL决定,而由其他外置条件决定的场景,可使用SQLHint灵活的注入分片字段。例:内部系统,按照员工登录主键分

  • hdu 5296,15年多校1-7

    题意:   给定一个无向带权图G(n,m),一个人要沿着最短路从1走到n,现在可以任意从图上删边。求,最少删多少边可以使之无法到达终点 和 最多删多少边其仍可以到达终点 想法:   比赛时的想法:直接跑最小费用最大流,spfa的时候维护一个最短路的值(min_dist),如果当前求得增广路径的最短路的值大于min_dist,肯定后面的最短路就都大于min_dist了,此时就已经求出最大流即第一问的答案了。在求增广路径的过程中维护所有最短路的最小边数,总边数减去最小边数就是即为第二问的答案。(没有觉得思路有什么问题,赛后对着数据,总是有两组跑的特别慢并且答案也是错的)。   后来按照标程写了一个,先一遍spfa求出所有最短录,并且得到最少边数。然后遍历所有边将最短路建图(这个图是根据最短路中dist值建的有向图),在新图上跑一遍最大流。结果两组数据还是过不去。   现记下来,回头补上。 武大训练第10场又挂了这个题,比赛时候补上了。 这是题解说的先最短路,重新建图再跑网络流的做法 2015-9-12补充,费用流没法做,因为在求增广路的时候会改变图中最短路上边

  • 机器学习:scipy和sklearn中普通最小二乘法与多项式回归的使用对

      相关内容连接:  机器学习:Python中如何使用最小二乘法(以下简称文一)  机器学习:形如抛物线的散点图在python和R中的非线性回归拟合方法(以下简称文二)    有些内容已经在上面两篇博文中提到了,所以就不重复了。这里主要讲的是sklearn包与scipy包中相关函数的区别。并且多项式回归和普通最小二乘法联系比较紧密,所以也放到此处讲了。 1.普通最小二乘法   1)文一中的数据采用sklearn包的函数拟合    fromsklearnimportlinear_model importnumpyasnp importmatplotlib.pyplotasplt ##样本数据(Xi,Yi),需要转换成数组(列表)形式 Xi=np.array([6.19,2.51,7.29,7.01,5.7,2.66,3.98,2.5,9.1,4.2]).reshape(-1,1) Yi=np.array([5.25,2.83,6.41,6.71,5.1,4.23,5.05,1

  • 【NOIP2017】蚯蚓

    有n只蚯蚓,每次选取一条最长的,按比例切成两半 然后其它没有被切的全部增加一个长度q 问每次切的是哪条蚯蚓,最后所有蚯蚓的长度是多少 复制 朴素的暴力想法: 类似于合并石子,使用一个堆来储存长度,每次取出堆顶切成两半 其它蚯蚓增加长度=这两半减少长度 输出的时候加上总增加长度即可 但考虑一下,需要优先队列来储存吗? 可以证明,无论哪种情况,先切的蚯蚓两半的长度一定大于后切的蚯蚓两半的长度 自带单调性啊 所以我们直接开三个数组,分别存原长,切了后第一段长度,切了后第二段长度 每次取出三个数组第一个元素的最大值操作即可 这三个数组不是堆,因为操作过程本身就保证了单调性 代码: #include<bits/stdc++.h> #defineN10000005 usingnamespacestd; intn,m,q,u,v,t,x,y; inta[N],b[N],c[N]; inthead=1,tail,head1=1,head2=1,tail1=0,tail2=0; intlst[N*10],cnt; intsigma; template<classT>inlin

  • C语言中&quot;.&quot;与&quot;-&gt;&quot;的区别

    在学习STM32的过程中遇到了许多定义的结构体,这就有必要了解一下"."与"->"的区别。 其实简单来说可以理解为: (*a).b等价于a->b。 "."一般情况下读作"的”,结构体a的b。 “->”一般读作"指向的结构体的",a指向的结构体的b。

  • 京东精益敏捷教练分享:敏捷助力产品创新!

      李国柱-京东精益敏捷教练   导语: 一般我们想到产品创新,会觉得这个是产品经理的事,是产品经理应该关心的,我们研发团队好像一般关注比较少。根据我自己的经验我发现在创新上面非常强的团队,通常研发团队有非常深的参与度,而且对整个创新过程的支撑是非常强。 敏捷思维在创新过程其实也能够扮演很关键的角色,接下来我结合自己的工作经历跟大家分享一下,在产品创新过程当中如何做到敏捷思想和敏捷实践起到助推产品创新的效果。 一、产品创新面临的挑战 首先我们在企业里工作中会做各种各样的创新尝试,大到产品的全新业务模式的建立或者旧有业务模式的重构,小到用户体验的提升,非常非常的多。产品经理可能有一些不错的想法抛出来,我们研发团队来帮助实现,这个过程会投入到很多的人力或者很多的金钱,最后结果如何呢?相当多的结果是非常不确定,很有可能达不到我们需要的这种效果。也就是说其实是非常不确定性,有非常多的不确定性,或者是成功的机会其实并不是非常的高。   ​   根据我自己的经验做过一些统计,互联网行业新产品成功率,我自己的经验不会超过5%。之前一家公司我参与产品的创新和

  • PHP使用Mongodb

    一.安装Mongodb的PHP扩展 wgethttp://pecl.php.net/get/mongo-1.2.7.tgz//下载扩展包tarzxvfmongo-1.2.7.tgzcdmongo-1.2.7/usr/local/php/bin/phpize./configure-with-php-config=/usr/local/php/bin/php-configmake makeinstall 注:当在ubuntu环境下,需要root权限,需要加sudo,故sudomake&&makeinstall会报ERROR,应该是sudomake&&sudomakeinstall才行,因为makeinstall也需要root权限才行。   二、Mongodb的CRUDAPI 1.连接Mongodb获取集合 $conn=newMongoClient("mongodb://127.0.0.1:27017");$db=$conn->mydb;$collection=$db->user;   2.Insert操作 $u1=array(

相关推荐

推荐阅读