Java学习(集合专栏附一点点Lambda)

集合框架
在这里插入图片描述
对于对象集合,必须执行的操作主要以下三种:

  • 添加新的对象
  • 删除对象
  • 查找对象
    集的基本属性如下:
  • 集内只包含每项的一个实例
  • 集可以是有限的,也可以是无限的。
  • 可以定义抽象概念

映射是一种特别的集。它是一种对(pair)集合,每个对表示一个元素到另一元素的单向映射。

“集合框架”由一组用来操作对象的接口组层。不同接口描述不同类型的组。

Java容器类类库的用途是保存对象,并将其划分两个不同的概念:
(1)Collection。一组对立的元素,通常这些元素都服从某种规则。List必须保持元素特定的顺序,而Set不能有重复元素。
(2)Map。一组成对的键值对对象。初看起来这似乎应该是一个Collection,其元素是成对的对象,但是这样的设计实现起来太笨拙了,于是我们将Map明确的提取出来形成一个独立概念。另一方面,如果使用Collection表示Map的部分内容,会便于查看此部分内容。因此Map一样容易扩展成多维Map,无需增加新的概念,只要让Map中的键值对的每个值也是一个Map即可。

Collection和Map的区别在于容器中每个位置保存的元素个数。Collection每个位置只能保存一个元素(对象)。此类容器包括:List,它以特定的顺序保存一组元素(对象)。此类容器包括:List,它以特定的顺序保存一组元素;Set则是元素不能重复。
Map保存的是键值对,就像一个小型数据库。我们可以通过键找到该键对应的值。

  • Collection 对象之间没有指定的顺序,允许重复元素
  • Set 对象之间没有指定的顺序,不允许重复元素。
  • List 对象之间有指定顺序,允许重复元素,并引入位置下标
  • Map 接口用于保存关键字(Key)和数值(Value)的集合,集合中的每个对象加入时都提供数值和关键字。Map接口既不继承Set也不继承Collection
    List、Set、Map共同的实现基础是Object数组。

除了四个历史集合类外,Java2框架还引入了六个集合实现,如下:
接口 实现 历史集合类
Set HashSet
TreeSet
List ArrayList Vector
LinkedList Stack
Map HashMap Hashtable
TreeMap Properties

任何集合(Collection)都能产生一个迭代器(Iterator),而一个List除了能生成一个ListIterator(列表迭代器)外,还能生成一个普通迭代器。

Collection
Collection接口用于表示任何对象或元素组。想要尽可能以常规方式处理一组元素时,就使用这一接口。Collection是List和Set的父类。并且它本身也是一个接口。
集合必须只有对象,集合中的元素不能是基本数据类型。

Collection接口支持如添加和除去等基本操作。设法除去一个元素时,如果这个元素存在,除去的仅仅是集合中此元素的一个实例。

  • boolean add(Object element)
  • boolean remove(Object element)
    Collection接口还支持查询操作:
  • int size()
  • boolean isEmpty()
  • boolean contains(Object element)
  • Iterator iterator()
    组操作:Collection接口支持的其它操作,要么是作用于元素组的任务,要么是同时作用于整个集合的任务。
  • boolean containsAll(Collection collection)
  • boolean addAll(Collection collection)
  • void clear()
  • void removeAll(Collection collection)
  • void retainAll(Collection collection)
    containAll()方法允许您查找当前集合是否包含了另一个集合的所有元素,及另一个集合是否是当前集合的子集。其余方法是可选的。因为特定的集合可能不支持集合更改。addAll()方法确保另一个集合中的所有元素都添加到当前的集合中,通常称为并。Clear()方法从当前集合中除去所有元素。RemoveAll()方法类似于clear(),但只除去了元素的一个子集。RetainAll()类似于removeAll()方法,不过它所做的与前面正好相反;它从当前集合中除去不属于另一个集合的元素,即交。
    因为Collection的实现基础是数组,所以有转换为Object数组的方法:
  • Object[] toArray()
  • Object[] toArray(Object[] a)
    其中第二个方法Object[] toArray(Object[] a)的参数a应该是集合中所有存放的对象的类的对象。

迭代器
迭代器的概念,也是处于一种设计模式就是为达成此目的而形成的。所以Collection不提供get()方法。如果要遍历Collection中的元素,就必须用Iterator。
迭代器(Iterator)本身就是一个对象,它的工作就是遍历并选择集合序列中的对象,而客户端的程序员不必知道或关心该序列底层的结构。此外,迭代器通常被称为轻量级对象,创建它的代价小。但是,它也有一些限制,例如,某些迭代器只能单向移动。
Collection接口的iterator()方法返回一个Iterator。Iterator与Enumeration接口类似。使用Iterator接口方法,可以从头至尾遍历集合,并安全的从底层Collection中除去元素。

Java的Collection的Iterator能够用来:
(1)使用方法Iterator()要去容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回集合序列的第一个元素。
(2)使用next()获得集合序列中的下一个元素。
(3)使用hasNext()检查序列中是否有元素。
(4)使用remove()将迭代器新返回的元素删除。

需要注意:方法删除由next方法返回的最后一个元素,在每次调用next时,remove方法只能被调用一次。

List
Collection接口实际上并没有直接的实现类。而List是容器的一种,表示列表的意思。当我们不知道存储的数据有多少的情况,我们就可以使用List来完成存储数据的工作。List的最大的特点就是能够自动的根据插入的数据量来动态改变容器的大小。
List接口不但能够对列表的一部分进行处理,还添加了面向位置的操作。List是按对象的进入顺序进行保存对象,而不做排序或编辑操作。
面向位置的操纵包括插入某个元素或Collection的功能,还包括获取、除去或更改元素的功能。在List中搜索元素可以从列表的头部或尾部开始,如果找到元素,还将报告元素所在的位置。

  • void add(int index, Object element): 添加对象element到位置index上
  • boolean addAll(int index, Collection collection): 在index位置后添加容器collection中所有的元素
  • Object get(int index): 取出下标为index的位置的元素
  • int indexOf(Object element):查找对象element在List中第一次出现的位置。
  • int lastIndexOf(Object element):查找对象element在List中最后出现的位置
  • Object remove(int index):删除index位置上的元素
  • Object set(int index, Object element):将index位置上的对象替换为element并返回老的元素。

在这里插入图片描述

List接口不但以位置友好的方式遍历整个列表,还能处理集合的子集。

  • ListIterator listIterator(): 返回一个ListIterator迭代器,默认开始位置为0。
  • ListIterator listIterator(int startIndex);返回一个ListIterator迭代器,开始位置为startIndex
  • List subList(int fromIndex, int toIndex):返回一个子列表,元素存放为从fromIndex到toIndex之前的一个元素。(对子列表的更改对底层List也有影响)。

ListIterator接口
ListIterator接口继承Iterator接口以支持添加或更改底层集合中的元素,还支持双向访问。

Map
映射关系在Java中就是通过Map来实现的。它表示,里面存储的元素是一个对(pair),我们通过一个对象,可以在这个映射关系中找到另一个和这个对象相关的东西。
Map接口不是Collection接口的继承。而是从自己的用于维护键-值关联的接口层次结构入手。按定义,该接口描述了从不重复的键到值的映射。
我们可以把这个接口方法分成三个操作:改变、查询和提供可选视图。
改变操作允许从映射中添加和除去键-值对。键和值都可以为null。但是不能把Map作为一个键或值添加给自身。

  • Object put(Object key, Object value):用来存放一个键-值对Map中
  • Object remove(Object key):根据Key(键),移除一个键-值对,并将值返回
  • void putAll(Map mapping): 将另一个Map中的元素存入当前的Map中
  • void clear(): 清空当前Map中的元素
    查询操作允许检查映射内容
  • Object get(Object key):根据(键)取得对应的值
  • boolean containsKey(Object key):判断Map中是否存在某键(key)
  • boolean containsValue(Object value):判断Map中是否存在某值(value)
  • int size(): 返回Map中键-值对的个数
  • boolean isEmpty():判断当前Map是否为空。
    提供可选视图操作允许把键或值的组作为集合来处理
  • public Set keySet():返回所有的键(key),并使用Set容器存放
  • public Collection values():返回所有的值(Value),并使用Collection存放
  • public Set entrySet():返回一个实现Map.Entry接口的元素Set

因为映射中键的集合必须是唯一的,就使用set来支持。因为映射中值的集合可能不唯一。就使用Collection来支持。最后一个方法返回一个实现Map.Entry接口的元素Set。
在这里插入图片描述在这里插入图片描述

HashMap的存入顺序和输出顺序无关。而ListedHashMap则保留了键值对的存入顺序。TreeMap则是对Map中的元素进行排序。
需要注意的是,TreeMap中是根据键(key)进行排序的,而如果我们要使用TreeMap来进行正常的排序话,Key中存放的对象必须实现Comparable接口。

Comparable接口
Comparable接口适用于一个类有自然顺序的时候。假定对象集合时同一类型,该接口允许把集合排序成自然顺序。
它只有一个方法。comparaTo()方法,用来比较当前实例和作为参数传入的元素。如果排序过程中当前实例出现在参数前(当前实例比参数大), 就返回某个负值。如果当前实例出现在参数后(当前实例比参数小),则返回正值。否则,返回零。如果这里不要求零返回值表示元素相等。零返回值可以只是两个对象在排序的时候排在同一个位置。
在Java2 SDK,版本1.2中有十四个类实现Comparable接口。
在这里插入图片描述
在集合框架中,接口Map和Collection在层次结构没有任何亲缘关系,它们是截然不同的。这种差别的原因与Set和Map在Java库中使用的方法有关。Map的电信那个应用是访问按关键字存储的值。它支持一系列集合操作的全部,但操作的是键值对,而不是单个独立的元素。因此Map需要get()和put()的基本操作,而Set不需要。此外,还有返回Map对象的Set视图的方法。

Hash,一般翻译做“散列”,就是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这个转换是一种压缩映射,也就是散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。

Hash算法的意义在于提供了一种快速存取数据的方法,它用一种算法建立键值与真实值之间的对应关系,(每一个真实值只能有一个键值,但是一个键值可以对应多个真实值),这样可以快速在数组等里面存取数据。

Hash表和Hash算法的特点就是它的存取速度比数组差一点,但是比起单纯的链表,在查找和存储方面却要好很多。同时数组也不利于数据的重构而排序等方面的要求。

HashMap的主要的构造函数
HashMap(int initialCapacity, float loadFactor)
该构造函数:
1.首先是判断int initialCapacity和float loadFactor是否合法
2.然后确定Hash表的初始化长度。确定的策略是:通过传进来的参数initialCapacity来找出第一个大于它的2的次方的数。比如说传了18这样一个initialCapacity参数,那么真实的table数组的长度为2的5次方,即32。之所以采用这种策略来构建Hash表的长度,是因为2的次方运算对于现代的处理器来说,可以通过一些方法得到更加好的效率。
3.接下来就是得到重构因子(threshold)了,这个属性也是HashMap中的一个比较重要的属性,它表示,当Hash表中的元素被存放了多少个后,我们就需要对该Hash表进行重构。
4.最后就是使用得到的初始化参数capacity来构建Hash表:Entry[] table。

一个键值对如何添加到HashMap中
如果Map中已经存在相同的键的键值对,那么就把新的值覆盖老的值,并把老的值返回给方法的调用者。如果不存在一样的键,那么就返回null。
1.首先我们判断如果key为null则使用一个常量来代替该key值,该行为在maskNull()终将key替换为一个非null的对象k
2.计算key值的Hash码:hash
3.通过使用Hash码来定位,我们应该把当前的键值对存放到Hash表中的哪个格子中。IndexFor()方法计算出的结果:i就是Hash表(table)中的下标。
4.然后遍历当前Hash表中table[i]格中的链表。从中判断是否已经存在一样的键(key)的键值对。如果存在一样的key的键,那么就用新的value覆写老的value,并把老的value返回
5.如果遍历后发现没有存在同样的键值对,那么就增加当前键值对到Hash表中的第i个格子中的链表中。并返回null。

重构Hash表的方法:void resize(int newCapacity)的实现方法:
1.首先判断如果Hash表的长度已经达到最大值,那么就不进行重构了。因为这个时候Hash表的长度已经达到上限,已经没有必要重构了。
2.然后就是构建新的Hash表
3.把老的Hash表中的对象数据全部转移到新的Hash表newTable中,并设置新的重构因子threshold。

覆写hashCode()
设计hashCode()时最重要的因素就是:无论何时,对同一个对象调用hashcode()都应该生成同样的值。如果在将一个对象用put()方法添加进HashMap时产生一个hashCode()值,而用get()取出时却产生了另外一个hashCode()值,那么就无法重新取得该对象了。

Set
Java中的Set正好和数学上直观的集(Set)的概念是相同的。Set最大的特性就是不允许在其中存放的元素是重复的。
常用方法:

  • public int size():返回set中元素的数目,如果set包含的元素数大于Integer.MAX_VALUE,返回Integer.MAX_VALUE
  • public boolean isEmpty():如果set中不含元素,返回true
  • public boolean contains(Object o):如果set包含指定元素,返回true
  • public Iterator iterator()
  • 返回set中元素的迭代器
  • 元素返回没有特定的顺序
  • public Object[] toArray():返回包含set中所有元素的数组
  • public Object[] toArray(Object[] a):返回包含set中所有元素的数组,返回数组的运行时类型是指定数组的运行时类型
  • public boolean add(Object o):如果set中不存在指定元素,则向set加入
  • public boolean remove(Object o):如果set中存在指定元素,则从set中删除
  • public boolean removeAll(Collection c):如果set包含指定集合,则从set中删除指定集合的所有集合。
  • public boolean addAll(Collection c):如果set中不存在指定集合的元素,则向set中加入所有元素。
  • public boolean retainAll(Collection c):只保留set中所含的指定集合的元素(可选操作)。换言之,从set中删除所有指定集合不包含的元素。如果指定集合也是一个set,那么该操作修改set的效果是使它的值为两个set的交集。
  • public boolean removeAll(Collection c):如果set包含指定集合,则从set中删除指定集合的所有元素。
  • public boolean removeAll(Collection c):如果set包含指定集合,则从set中删除指定集合的所有元素。
  • public void clear(): 从set中删除所有元素。

“集合框架”支持set接口两种普通的实现:HashSet和TreeSet以及LinkedHashSet。
在这里插入图片描述

我们可以知道HashSet的元素存放顺序和我们添加进去时候的顺序没有任何关系,而LinkedHashSet则保持元素的添加顺序。TreeSet则是对我们的Set中的元素进行排序存放。

Set利用的就是Map中键不能重复的特性来实现的。
建立一个键值对。键就是我们要存入的对象,值则是一个常量。这样可以确保我们所需要存储的信息是键。而键在Map中是不能重复的,这就保证了我们存入Set中的所有的元素都不重复。而判断是否添加元素成功,则是通过判断我们向Map中存入的键值对是否,如果存在的话,那么返回值肯定是常量:PRESENT,表示添加失败。如果不存在,返回值就为null表示添加成功。
在这里插入图片描述
在这里插入图片描述

Lambda表达式
Lambda表达式,也可以称为闭包,它是推动Java8发布的最重要的新特性。
Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中)
使用Lambda表达式可以使代码变得更加紧凑

语法
Lambda表达式的语法格式如下:
(parameters)->expression 或(parameters) ->{statements;}
以下是lambda表达式的重要特征:
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

Lambda表达式实例:
1.不需要参数,返回值为5
() -> 5
2.接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
3.接受2个参数(数字),并返回他们的差值
(x,y) -> x - y
4.接收2个int型整数,返回他们的和
(int x, int y) -> x + y
5.接受一个string对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)

使用Lambda表达式需要以下两点:

  • Lambda表达式主要用来定义行内执行的方法类型接口。
  • Lambda表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力

变量作用域
Lambda表达式只能引用标记了final的外层局部变量,这就是说不能再Lambda内部修改定义在域外的局部变量,否则会编译失败。

Lambda表达式的局部变量可以不用声明为final,但是必须不可被后面的代码修改(即隐性的具有final的语义)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值