ArrayList成员方法
方法名 | 说明 |
Boolean add(E e) | 添加元素,返回值表示是否添加成功 |
boolean remove(E e) | 删除指定元素,返回值表示是否删除成功 |
E remove(int index) | 删除指定索引的元素,返回被删除的元素 |
E set(int index,E e) | 修改指定索引下的元素,返回原来的元素 |
E get(int index) | 获取指定索引元素 |
int size() | 集合的长度,也就是集合中元素的个数 |
packagegather;
importjava.util.ArrayList;
/*
boolean add(E e) 添加
boolean remove(E e) 删除
E remove(int index)
E set(int index,E e) 修改
E get(int index) 查询
int size() 获取长度
*/
publicclassDemo02 {
publicstaticvoidmain(String[] args) {
//1.创建一个集合
ArrayList<String>list=newArrayList<>();
//2.添加元素
booleanresult=list.add("aaa");
list.add("ccc");
list.add("bbb");
list.add("ddd");
list.add("eee");
System.out.println(result);
//3.删除元素
list.remove("aaa");
list.remove(1);
//4.修改元素
list.set(1,"fff");
//5.查询元素
Strings=list.get(2);
System.out.println(s);
//遍历
for (inti=0; i<list.size(); i++) {
//i 索引
//list.get(i)元素
Strings1=list.get(i);
System.out.println(s1);
}
System.out.println(list);
}
}
基本数据类型对应的包装
byte | Byte |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
集合的体系结构
Collection:单列集合
分为:list系列集合:添加的元素是有序,可重复,有索引
包括:ArrayList, LinkedList, Vector
Set系列集合:添加的元素是无序,不重复,无索引
包括:HashSet(又包括LinkedHashSet), TreeSet,
Map:双列集合
Collection集合
Collection是单集合的祖宗接口,它的功能是全部单列集合都可以继承使用的
方法名称 | 说明 |
public boolean add(E e) | 把给定对象添加到当前集合中 |
public void clear() | 清空集合中所有对象 |
public boolean remove(E e) | 把给定对象在当前集合中删除 |
public boolean contains(Object obj) | 判断当前集合中是否包含给定的对象 |
public boolean isEmpty() | 判断当前集合是否为空 |
public int size() | 返回集合中元素的个数/集合的长度 |
Collection<String>coll=newArrayList<>();
//1.添加元素
//细节1:如果我们要往List系列集合中添加数据,那么方法永远返回true,因为List系列的时允许元素重复的
//细节2:如果我们要往Set系列集合中添加数据,如果要添加的元素不存在,方法返回true,表示添加成功
// 如果当前要添加的元素已经存在,方法返回false,表示添加失败
coll.add("aaa");
System.out.println(coll);
//2.清空集合中所有对象 clear()
coll.clear();
System.out.println(coll);
//3.把给定对象在当前集合中删除 remove(E e)
//细节1:因为Collection里面定义的是共性的方法,所以此时不能通过索引进行删除,只能通过元素对象进行删除
//细节2:方法会有一个布尔类型的返回值,删除成功返回true,删除失败返回false
//如果删除元素不存在,就会删除失败
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.remove("aaa");
System.out.println(coll);
//4.判断当前集合中是否包含给定的对象 contains(Object obj)
//细节:底层依赖的是equals方法进行判断是否存在
//细节:如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在
//Javabean类中,一定要重写equals方法
booleanb=coll.contains("aaa");
System.out.println(b);
//5.判断当前集合是否为空 isEmpty()
booleane=coll.isEmpty();
System.out.println(e);
//6.返回集合中元素的个数/集合的长度 size()
intsize=coll.size();
System.out.println(size);
Collection的遍历方式:
1.迭代器遍历:迭代器在java中的类是Iterator,迭代器是集合专用的遍历方式
Collection集合获取迭代器
方法名称 | 说明 |
Iterator<E> iterator() | 返回迭代器对象,默认指向当前集合0索引 |
Iterator中常用的方法
方法名称 | 说明 |
Boolean hasNext() | 判断当前位置是否有元素,有元素返回true,没有元素返回false |
E next() | 获取当前位置的元素,并将迭代器对象移向下一个位置 |
//1.创建集合并添加元素
Collection<String>coll=newArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");
//2.获取迭代器的对象
//迭代器好比是一个箭头,默认指向集合的0索引处
Iterator<String>it=coll.iterator();
//3.判断当前位置是否有元素,有元素返回true,没有元素返回false hasNext()
while (it.hasNext()) {
//4.获取当前位置的元素,并将迭代器对象移向下一个位置 next()
Strings=it.next();
System.out.println(s);
细节注意点:
1.迭代器指向最后继续调用会报错NoSuchElementExpetion
2.迭代器遍历完毕,指针不会复位
3.循环中只能用一次next方法
4.迭代器 遍历时,不能用集合的方法进行增加或删除
2.增加for遍历
增强for的底层就是迭代器,为了简化迭代器的代码书写的
他是JDK5之后出现的,其内部原理就是一lterator迭代器
所有的单列集合和数组才能用增强for循环遍历
格式:
for(元素的数据类型变量名:数组或者集合){}
//1.创建集合并添加元素
Collection<String>list=newArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
//2.循环遍历
for (Strings : list) {
System.out.print(s+" ");
}
修改增强for中的变量,不会改变集合中原本的数据
3.Lambda表达式遍历
得益于JDK8开始的新技术Lambda表达式,提供了一种更简单,更直接的遍历集合的方式
方法名称 | 说明 |
default void forEach(Consumer<? super T> action) | 结合Lambda遍历集合 |
//1.创建集合并添加元素
Collection<String>list=newArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
//利用匿名内部类的形式
//底层原理:
//遍历集合依次得到每一个元素
//把得到的每一个元素,传递给下面accept方法
//s依次表示集合中的每一个数据
list.forEach(newConsumer<String>() {
@Override
publicvoidaccept(Strings) {
System.out.println(s);
}
});
//Lambda表达式遍历
list.forEach(s->System.out.println(s));
List集合
List集合的特点
有序:存和取的元素一致
有索引:可以通过索引操作元素
可重复:存储的元素可以重复
List集合的特有方法
Collection的方法都继承了
List集合因为有索引,所以多了很多索引操作的方法
方法名称 | 说明 |
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(in index) | 返回指定索引处的元素 |
List集合的遍历方式
迭代器遍历:在遍历的过程中需要删除元素,请使用迭代器
列表迭代器遍历:在遍历的过程中需要添加元素,请使用列表迭代器
增强for循环:仅仅想遍历,那么使用增加for或Lambda表达式
Lambda表达式遍历:仅仅想遍历,那么使用增加for或Lambda表达式
普通for循环(因为List集合存在索引):如果遍历的时候想要操作索引,可以用普通的for
//1.迭代器遍历
Iterator<String>it=list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//2.增强for循环
/*for (String s : list) {
System.out.println(s);
}*/
//3.Lambda表达式遍历
// list.forEach(s -> System.out.println(s));
//4.普通for循环(因为List集合存在索引)
/* for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}*/
//5.列表迭代器遍历
/* ListIterator<String> it = list.listIterator();
while (it.hasNext()){
System.out.println(it.next());
}*/
ArrayList集合
数据结构概述
数据结构是计算机底层存储,组织数据的方式。
是指数据相互之间以什么方式排列在一起的。
数据结构是为了更加方便的管理和使用数据,需要结合具体业务场景来进行选择
一般情况下,精心选择的数据结构可以代开更高的运行或者存储效率
数据结构(栈)
栈的特点:后进先出,先进后出
数据进入栈模型的过程称为:压/栈
数据结构(队列)
队列的特点:先进先出,后进后出
数据从后端进入队列模型的过程称为:入队列
数据从前端离开队列模型的过程称为:出队列
数据结构(数组)
数组是一种查询快,增删慢的模型
查询速度块:查询数据通过地址值和索引定位,查询任意数据耗时相同。(元素在内存中是连续存储的)
删除效率低:要将原始数据删除,同时后面每个数据前移
添加效率极低:添加位置后的每个数据后移,再添加元素
数据结构(链表)
链表中的结点是独立的对象,在内存中不是连续的,每个节点包含数据值和下一个结点的地址
链表查询慢,无论查询哪个数据都要从头开始找
链表增删相对快
ArrayList集合底层原理
1.利用空参创建的集合,在底层创建一个默认长度为0的数组
2.添加第一个元素的时候,底层会创建一个新的长度为10的数组 数组名字:elementData
3.存满时,会扩容1.5倍
4.如果一次添加多个数据,1.5倍还放不下,则新创建数组的长度以实际为准
ArrayList<String>list=newArrayList<>();//默认长度为0
list.add("aaa");//添加第一个元素
public boolean add(E e){
modCount++;
add(e,elementData,size);//参数1:当前要添加的元素
//参数2:集合底层的数组名字
return true; //参数3:集合的长度/当前元素应存入的位置
}
private void add(E e,Object[] elementData,int s){
if(s == elementData.length){
elementData = grow();//grow():表示数组扩容
elementData[s] = e;
size = s + 1;
}
}
private Object[] grow(){
return grow(size + 1);//把现有的个数+1
}
privateObject[] grow(intminCapacity){
intoldCapacity=elementData.length;//记录原来的老容量
if(oldCapacity>0||elementData!=DEFAULTCAPACITY_EMPTY_ELEMENTDATA){
intnewCalacity=ArraysSupport.newlength(oldCapacity,minCapacity-oldCapacity,
oldCapacity>>1);//在后面需要扩容就会执行if
returnelementData=Arrays.copyOf(elementData,newCapacity);
}else{
returnelemendData=newObject[Math.max(DEFAULT_CAPACITY,minCapacity)];
}//第一次添加数据的时候,会执行到else这里
}
publicstaticintnewLength(intoldLength,intminGrowth,intprefGrowth){
intprefLength=oldLength+Math.max(minGrowth,prefGrowth);
if(0<prefLength&&prefLength<=SOFT_MAX_ARRAY_LENGTH){
renturnprefLength;
}else{
returnhugelength(oldLength,minGrowth);
}
}
LinkedList集合
底层数据结构是双链表,查询慢,增删快,但是如果操作的是首位元素,速度也是极快的。
LinkedList本身多了很多直接操作首位元素的特有API
特有方法 | 说明 |
public void addFirst(E e) | 在该列表开头插入指定元素 |
public void addList(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast | 返回此列表中的最后一个元素 |
public E removeFirst() | 从列表中删除并返回第一个元素 |
public E removeLast() | 从列表中删除并返回最后一个元素 |
泛型深入
泛型:是JDK5中引用的特性,可以在编译阶段约束操作的数据类型,并进行检查
泛型的格式:<数据类型>
注意:泛型只支持引用数据类型
如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型,此时可以往集合里添加任意数据类型
坏处:我们在获取数据的时候,无法使用他的特有行为
此时推出泛型,可以在添加数据的时候把类型统一,而且我们在获取数据的时候,也省得强转了,非常方便
泛型类
使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带泛型的类
//格式
修饰符 class 类名<类型>{
}
package com.cjj.mygenerics;
import java.util.Arrays;
/*
当我们在编写一个类的时候,如果不确定类型,那么这个类就可以定义为泛型类
*/
public class MyArrayList<E>{//此处的E可以理解为变量,但是不是用来记录数据的,而实记录类型,可以写成:T,E,K,V,等等
Object[] obj = new Object[10];
int size;
/*
E:表示是一个不确定的类型,该类型在类名后面以及定义过了
e:形参的名字
*/
public boolean add(E e){
obj[size] = e;
size++;
return true;
}
public E get(int index) {
return (E)obj[index];
}
@Override
public String toString() {
return Arrays.toString(obj);
}
}
泛型方法
方法中形参类型不确定时,可以用类名后面定义的泛型<E>
方案1:使用类名后面定义的泛型(所有方法都能用)
方案2:在方法申明上定义自己的泛型(只能本方法能用)
//格式
修饰符 <类型> 返回值类型 方法名(类型 变量名){
}
public static<E> void addAll(ArrayList<E> list,E e1,E e2,E e3,E e4) {
list.add(e1);
list.add(e2);
list.add(e3);
list.add(e4);
}
泛型接口
//格式
修饰符interface接口名<类型>{}
方式1:实现类给出具体类型
方式2:实现类延续泛型,创建对象时再确定
泛型的继承和通配符
泛型不具备继承性,但是数据具有继承性
泛型的通配符:
?也表示不确定的类型
它可以进行类型的限定
?extends E:表示可以传递E或者E所有的子类类型
? super E:表示可以传递E或者E所有的父类类型
应用场景:
1.如果我们在定义类,方法,接口的时候,如果类型不确定,就可以定义泛型类,泛型方法,泛型接口。
2.如果类型不确定,但是能知道,但是能知道以后只能传递某个继承体系中的,就可以泛型的通配符
泛型的通配符:
关键点:可以限定类型的范围
总结:
1.什么是泛型?
JDK5引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
2.泛型的好处?
①:统一数据类型
②:把运行时期的问题提前到了编译的阶段,避免了强制类型的转换可能出现的异常,因为在编译阶段类型就能确定下来了
3.泛型的细节?
①:泛型中不能写基本数据类型
②:指定泛型的具体类型后,传递数据时,可以传入该类型和他的子类类型
③:如果不写泛型,类型默认Object
4.哪里定义泛型
①:泛型类:再类名后面定义泛型,创建该类对象的时候,确定类型
②:泛型方法:在修饰符后面定义方法,调用该方法的时候,确定类型
③:泛型接口:在接口后面定义泛型,实现类确定类型,实现类延续泛型
数据结构(树)
度:每一个节点的子节点数量
二叉树中,任意节点的度<=2
树高:树的总层数
根节点:最顶层的节点
左子节点:左下方的节点
右子节点:右下方的节点
根节点的左子树
根节点的右子树
二叉查找树
又称二叉排序树或者二叉搜索树
特点:
1.每一个节点上最多有两个子节点
2.任意节点左子树上的值都小于当前节点
3.任意节点右子树上的值都大于当前节点
添加节点:
规则:小的存左边,大的存有边,一样的不存
数据结构(二叉树)遍历方式
①前序遍历:从根节点开始,然后按照当前节点,左子节点,右子节点的顺序遍历
②中序遍历:从最左边的子节点开始,然后按照左子结点,当前结点,右子结点的顺序遍历
③后序遍历:从最左边的子节点开始,然后按照左子结点,右子结点,当前结点的顺序遍历
④层序遍历:从根节点一层一层的遍历
平衡二叉树
规则:任意节点左右子树的高度差不超过1
旋转机制:
确定支点:从添加的节点开始,不断的往父节点找不平衡的支点
规则1:左旋
规则2:右旋
触发机制:当添加一个节点之后,该树不再是一颗平衡二叉树
平衡二叉树需要旋转的四种情况
左左:当根节点左子树的左子树有节点插入,导致二叉树不平衡
一次右旋
左右:当根节点左子树的右子树有节点插入,导致二叉树不平衡
先局部左旋,再整体右旋
右右:当根节点右子树的右子树有节点插入,导致二叉树不平衡
一次左旋
右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡
先局部右旋,再整体左旋
红黑树
红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构
1972年出现,当时被称之为平衡二叉B树,后来,1978年被修改为如今的“红黑树”
他是一种特殊的二叉查找树,红黑树的每一个节点上都有存储表示节点的颜色
每一个节点可以是红或者黑;红黑树不是高度平衡的,它的平衡是通过“红黑规则”进行实现的
平衡二叉树:高度平衡
当左右子树高度差超过1时,通过旋转保持平衡
红黑树:是一个二叉查找树
但是不是高度平衡
条件:特有的红黑规则
数据结构(红黑树)红黑规则
①:每一个节点或是红色的,或者是黑色的
②:根节点必须是黑色的
③:如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
④:如果某一个节点是红色的,那么他的子节点必须是黑色(不能出现两个红色节点相连的情况)
⑤:对每一个节点,从该节点到期所有后代叶节点的简单路劲上,均包含相同数目的黑色节点
默认颜色:添加节点默认是红色的(效率高)
红黑树增删改查性能都很好
Set系列集合
无序:存取顺序不一样
不重复:可以去除重复
无索引:没有带索引的方法,所以不能使用普通的for循环遍历,也不能通过索引来获取元素
Set集合的实现类:
HashSet:无序,不重复,无索引
LinkedHashSet:有序,不重复,无索引
TreeSet:可排序,不重复,无索引
Set接口中的方法上基本上与Collection的API一致
HashSet
HashSet集合底层采取哈希表存储数据
哈希表是一种对于增删改查数据性能都较好的结构
哈希表组成
JDK8之前:数组加链表
① 创建一个默认长度16,默认加载因为0.75的数组,数组名为table
② 根据元素的哈希值根数组的长度计算出应存入的位置
int index = (数组长度-1) & 哈希值;
③ 判断当前位置是否为null,如果是null直接存入
④ 如果位置不为null,表示有元素,在调用equals方法比较属性值
⑤ 一样:不存 不一样:存入数组,形成链表
JDK8以前:新元素存入数组,老元素挂在新元素下面
JDK8以后:新元素直接挂在老元素下面
当链表长度超过8,而且数组长度大于等于64时,自动转换为红黑树
如果集合中存储的是自定义对象,必须要重写hashCode和equals方法
JDK8开始:数组+链表+红黑树
哈希值
对象的整数表现形式
根据HashCode方法算出来的int类型的整数
该方法定义再Object类中,所有对象都可以调用,默认使用地址值进行计算
一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值
对象哈希值特点
如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
如果已经重写了hashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)
LinkedHashSet
有序,不重复,无索引
这里的有序指的是保证存储和取出的元素顺序一致
原理:底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序
在以后如果要数据去重,我们使用哪个
默认使用HashSet
如果要求去重且存取有序,才使用LinkedHashSet
TreeSet
不重复,无索引,可排序
底层基于红黑树实现排序,增删改查性能较好
TreeSet集合默认的规则
对于数值类型:Integer,double,默认按照从大到小的顺序进行排序
对于字符。字符串类型:按照字符在ASCII的数字升序进行排序
TreeSet的两种比较方式
方式1:默认排序/自然排序:javabean类 实现Comparable接口指定比较规则
方式2:创建TreeSet对象的时候,传递比较强Comparator指定规则
使用原则:默认使用第一种,如果第一种不能满足当前需求,就使用第二种
总结
1.如果想要集合中的元素可重复
用ArrayList集合,基于数组的。(用的最多)
2.如果想要集合中的元素可重复,而且当前的增删操作明显多于查询
用LinkedList集合,基于链表的
3.如果相对集合中的元素去重
用HashSet集合,基于哈希表的。(用的最多)
4.如果想对集合中的元素去重,而且保证存取顺序
用LinkedHashSet集合,基于哈希表和双链表,效率低于HashSet
5.如果相对集合中的元素进行排序
用TreeSet集合,基于红黑树。后续也可以用List集合实现排序
双列集合的特点
① 双列集合一次需要存一对数据,分别为键和值
② 键不能重复,只值可以重复
③ 键和值是一一对应的,每一个键只能找到自己对应的值
④ 键+值这个整体我们称之为“键值对”或者“键值对对象”,在Java中叫做“Entry对象”
Map的常见API
Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的
方法名称 | 说明 |
V put(K key,V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
packagecom.cjj.a01mymap;
importjava.util.HashMap;
importjava.util.Map;
publicclassA01_MapDemo01 {
/*
| 方法名称 | 说明 |
| ----------------------------------- | ------------------------------------ |
| V put(K key,V value) | 添加元素 |
| V remove(Object key) | 根据键删除键值对元素 |
| void clear() | 移除所有的键值对元素 |
| boolean containsKey(Object key) | 判断集合是否包含指定的键 |
| boolean containsValue(Object value) | 判断集合是否包含指定的值 |
| boolean isEmpty() | 判断集合是否为空 |
| int size() | 集合的长度,也就是集合中键值对的个数 |
*/
publicstaticvoidmain(String[] args) {
//1.创建Map集合的对象
Map<String, String>m=newHashMap<>();
//2.添加元素 put(K key,V value)
//细节:
//再添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回null
//再添加数据的时候,如果键存在,那么就会把原有的键值对对象覆盖,会把被覆盖的值进行返回
m.put("怡宝","2元");
m.put("绿茶","3元");
m.put("红茶","3元");
m.put("外星人电解质水","5元");
m.put("脉动","4元");
System.out.println(m);
//3,根据键删除键值对元素 remove(Object key)
m.remove("绿茶");
System.out.println(m);
//4.移除所有的键值对元素 void clear()
m.clear();
System.out.println(m);
//2.添加元素 put(K key,V value)
m.put("怡宝","2元");
m.put("绿茶","3元");
m.put("红茶","3元");
m.put("外星人电解质水","5元");
m.put("脉动","4元");
System.out.println(m);
//5.判断集合是否包含指定的键 containsKey(Object key)
booleanb=m.containsKey("脉动");
System.out.println(b);
//6.判断集合是否包含指定的值 containsValue(Object value)
booleanb1=m.containsValue("5元");
System.out.println(b1);
//7.判断集合是否为空 isEmpty()
booleanb2=m.isEmpty();
System.out.println(b2);
//8.集合的长度,也就是集合中键值对的个数 size()
intsize=m.size();
System.out.println(size);
}
}
Map的遍历方式(键找值)
//3.1获取所有的键,把这些放到一个单列集合
Set<String> keys = m.keySet();
//3.2遍历单列集合,得到每一个键
for (String key : keys) {
//System.out.println(key);
//3.3利用map集合中的键获取对应的值 get
String value = m.get(key);
System.out.println(key+"="+value);
}
Map的遍历方式(键值对)
//4.Map集合遍历的第二种方式
//通过键值对对象进行遍历
//4.1通过一个方法获取所有的键值对对象,返回一个set集合
Set<Map.Entry<String, String>> e = m.entrySet();
//4.2遍历e这个集合,去得到里面的每一个键值对对象
for (Map.Entry<String, String> sse : e) {
String key = sse.getKey();
String value = sse.getValue();
System.out.println(key+"="+value);
//System.out.println(sse);
}
Map的遍历方式(Lambda表达式)
方法名称 | 说明 |
default void forEach(BiConsumer< ? super K, ? super V> action) | 结合lambda遍历Map集合 |
//利用lambda表达式进行遍历
m.forEach(( key, value)-> System.out.println(key+"="+value));
HashMap
HashMap的特点
① HashMap是Map里面的一个实现类
② 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
③ 特点都是由键决定的:无序,不重复,无索引
④ HashMap跟HashSet底层原理是一模一样的,都是哈希表结构
总结
1.HashMap底层是哈希表结构的
2.依赖hashCode方法和equals方法保证键的唯一
3.如果键存储的是自定义对象,需要重写hashCode和equals方法
如果值存储自定义对象,不需要重写hashCode和equals方法
LinkedHashMap
由键决定:有序,不重复,无索引
这里的有序指的是保证存储和取出的元素一致
原理:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序
TreeMap
TreeMap跟TreeSet底层原理一样,都是红黑树结构的。
由键决定:不重复,无索引,可排序
可排序:对键进行排序
注意:默认按照键的从大到小进行排序,也可以自己规定排序规则
代码实现两种排序规则
实现Comparable接口,指定比较规则
创建集合时传递Comparator比较器对象,指定比较规则
可变参数
JDK5引入的可变参数
作用:在形参中接收多个数据
方法的形参的个数是可以发生变化的
//格式
属性类型...名字
publicstaticvoidmain(String[] args) {
/*
格式
属性类型...名字
可变参数的细节
1.在方法中最多只能写一个可变参数
2.在方法中,如果出了,可变参数以外,还有其他的形参,那么就可变参数要写在最后
*/
getSum();
}
publicstaticintgetSum(int...args){
//底层:
//可变参数的底层就是一个数组
//只不过不需要我们自己创建了,Java会帮我们创建好
System.out.println(args);
return0;
}
Collections
java.util.Collection:是集合工具类
作用:Collections不是集合,而是集合的工具类
Collection常用的API
方法名称 | 说明 |
public static <T> boolean addAll(Collection<T> c, T... elements) | 批量添加元素 |
public static void shuffle(List<?> list) | 打乱List集合元素的顺序 |
public static <T> void sort(List<T> list) | 排序 |
public static <T> void sort(List<T> list, Comparator<T> c) | 根据制定规则进行排序 |
public static <T> int binaySearch(List<T> list, T Key) | 以二分查找法查找元素 |
public static <T> void copy(List<T> dest, List<T> src) | 拷贝集合中的元素 |
public static <T> int fill(List<T> list, T obj) | 使用指定的元素填充集合 |
public static <T> void max/min(Collection<T> coll) | 根据默认的自然排序获取最大/最小值 |
public static <T> void swap(List<?> list,int i,int j) | 交换集合中的指定元素 |
创建不可变集合
不能被修改的集合
应用场景
如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践
当集合对象被不可信的库调用时,不可变的形式是安全的
简单理解:不想让别人修改集合中的内容
创建不可变集合的书写格式
在List,Set,Map接口中,都存在静态的of方法,可以获取一个不可变集合
方法名称 | 说明 |
static <E> List<E> of(E……elements) | 创建一个就有指定元素的List集合 |
static <E> Set<E> of(E……elements) | 创建一个就有指定元素的Set集合 |
static <K,V> Map<K,V> of(E……elements) | 创建一个就有指定元素的Map集合 |
注意:这个集合不能添加,不能删除,不能修改
三种方式的细节
List:直接用
Set:元素不能重复
Map:元素不能重复,键值对数量最多10个,超过10个用ofEntries方法
Stream流
初识stream流
packagecom.cjj.a01mystreamdemo01;
importjava.util.ArrayList;
publicclassStreamDemo01 {
publicstaticvoidmain(String[] args) {
/*
创建集合添加元素,完成以下需求
1.把所有以”张“开头的元素存储到新集合中
2.把”张“开头的,长度为3的元素在存储到新集合中
3。遍历打印最终结果
*/
ArrayList<String>list1=newArrayList<>();
list1.add("张无忌");
list1.add("周芷若");
list1.add("赵敏");
list1.add("张强");
list1.add("张三丰");
list1.stream().filter(name->name.startsWith("张")).filter(name->name.length()==3).forEach(name->System.out.println(name));
/*//1.把所有以”张“开头的元素存储到新集合中
ArrayList<String> list2 = new ArrayList<>();
for (String name : list1) {
if(name.startsWith("张")){
list2.add(name);
}
}
System.out.println(list2);
//2.把”张“开头的,长度为3的元素在存储到新集合中
ArrayList<String> list3 = new ArrayList<>();
for (String name : list2) {
if(name.length()==3){
list3.add(name);
}
}
System.out.println(list3);*/
}
}
Stream流的使用步骤
作用:结合Lambda表达式,简化集合,数组的操作
1.先得到一条Stream流,并把数据放上去
获取方式 | 方法名 | 说明 |
单列集合 | default Stream<E> stream() | Collection中的默认方法 |
双列集合 | 无 | 无法直接使用stream流 |
数组 | public static <T> Stream<T> stream(T[] array) | Arrays工具类的静态方法 |
一堆零散的数据 | public static <T> Stream<T> of(T...values) | Stream接口中的静态方法 |
packagecom.cjj.a01mystreamdemo01;
importjava.util.ArrayList;
importjava.util.Collections;
publicclassStreamDemo02 {
publicstaticvoidmain(String[] args) {
/*
| 获取方式 | 方法名 | 说明 |
| -------------- | --------------------------------------------- | ---------------------- |
| 单列集合 | default Stream<E> stream() | Collection中的默认方法 |
| 双列集合 | 无 | 无法直接使用stream流 |
| 数组 | public static <T> Stream<T> stream(T[] array) | Arrays工具类的静态方法 |
| 一堆零散的数据 | public static <T> Stream<T> of(T...values) | Stream接口中的静态方法 |
*/
//单列集合 | default Stream<E> stream() | Collection中的默认方法
ArrayList<String>list=newArrayList<>();
Collections.addAll(list,"a","b","c","d");
/*//获取一条流水线,并把集合中的数据放到流水线上
Stream<String> stream1 = list.stream();
//使用终结方法打印一个流水线上的所有数据
stream1.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});*/
//可以采用链式编程
list.stream().forEach(s->System.out.println(s));
}
}
packagecom.cjj.a01mystreamdemo01;
importjava.util.HashMap;
publicclassStreamDemo03 {
publicstaticvoidmain(String[] args) {
//| 双列集合 | 无 | 无法直接使用stream流 |
//1.创建一个双链集合
HashMap<String,Integer>hm=newHashMap<>();
hm.put("aaa",111);
hm.put("bbb",222);
hm.put("ccc",333);
hm.put("ddd",444);
hm.put("eee",555);
hm.put("fff",666);
//3.获取Stream流
//hm.keySet().stream().forEach(s-> System.out.println(s));
hm.entrySet().stream().forEach(s->System.out.println(s));
}
}
packagecom.cjj.a01mystreamdemo01;
importjava.util.HashMap;
publicclassStreamDemo03 {
publicstaticvoidmain(String[] args) {
//| 双列集合 | 无 | 无法直接使用stream流 |
//1.创建一个双链集合
HashMap<String,Integer>hm=newHashMap<>();
hm.put("aaa",111);
hm.put("bbb",222);
hm.put("ccc",333);
hm.put("ddd",444);
hm.put("eee",555);
hm.put("fff",666);
//3.获取Stream流
//hm.keySet().stream().forEach(s-> System.out.println(s));
hm.entrySet().stream().forEach(s->System.out.println(s));
}
}
packagecom.cjj.a01mystreamdemo01;
importjava.util.stream.Stream;
publicclassStreamDemo05 {
publicstaticvoidmain(String[] args) {
//一堆零散的数据 | public static <T> Stream<T> of(T...values) | Stream接口中的静态方法
Stream.of(1,2,3,4,5).forEach(s->System.out.println(s));
}
}
2.使用中间方法对流水线上的数据进行操作
名称 | 说明 |
Stream<T> filter(Predicate<? super T> predicate) | 过滤 |
Stream<T> limit(long maxSize) | 获取前几个元素 |
Stream<T> skip(long n) | 跳过前几个元素 |
Stream<T> distinct() | 元素去重,依赖(HashCode和equals) |
static <T> Stream<T> concat(Stream a,Stream b) | 合并a和b两个流为一个流 |
Stream<R> map(Function<T,R>) mapper | 转换流中的数据类型 |
注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据
packagecom.cjj.a01mystreamdemo01;
importjava.util.ArrayList;
importjava.util.Collections;
publicclassStreamDemo06 {
publicstaticvoidmain(String[] args) {
/*
| Stream<T> filter(Predicate<? super T> predicate) | 过滤 |
| Stream<T> limit(long maxSize) | 获取前几个元素 |
| Stream<T> skip(long n) | 跳过前几个元素 |
注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据
*/
ArrayList<String>list=newArrayList<>();
Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰","张翠山","张良王","二麻子","谢广坤");
//1.Stream<T> filter(Predicate<? super T> predicate) | 过滤
/*list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
//如果返回值为true,则表示当前数据流下
//如果返回值为false,则表示当前数据舍弃不要
s.startsWith("张");
return true;
}
}).forEach(s-> System.out.println(s));*/
/*list.stream()
.filter(s->s.startsWith("张"))
.filter(s->s.length()==3)
.forEach(s-> System.out.println(s));*/
//Stream<T> limit(long maxSize) | 获取前几个元素 |
// | Stream<T> skip(long n) | 跳过前几个元素
/*list.stream()
.limit(6)
.forEach(s-> System.out.println(s));
list.stream()
.skip(3)
.forEach(s-> System.out.println(s));*/
list.stream().limit(6).skip(3).forEach(s->System.out.println(s));
}
}
packagecom.cjj.a01mystreamdemo01;
importjava.util.ArrayList;
importjava.util.Collections;
importjava.util.stream.Stream;
publicclassStreamDemo07 {
publicstaticvoidmain(String[] args) {
//| Stream<T> distinct() | 元素去重,依赖(HashCode和equals) |
//| ---------------------------------------------- | ---------------------------------- |
//| static <T> Stream<T> concat(Stream a,Stream b) | 合并a和b两个流为一个流 |
ArrayList<String>list=newArrayList<>();
Collections.addAll(list,"张无忌","张三丰","张三丰","周芷若","赵敏","张强","张三丰","张翠山","张良王","二麻子","谢广坤");
list.stream().distinct().forEach(s->System.out.println(s));
ArrayList<String>list2=newArrayList<>();
Collections.addAll(list2,"周芷若","赵敏");
Stream.concat(list2.stream(),list.stream()).forEach(s->System.out.println(s));
}
}
packagecom.cjj.a01mystreamdemo01;
importjava.util.ArrayList;
importjava.util.Collections;
importjava.util.function.Function;
publicclassStreamDemo08 {
publicstaticvoidmain(String[] args) {
/*
Stream<R> map(Function<T,R>) mapper转换流中的数据类型
*/
ArrayList<String>list=newArrayList<>();
Collections.addAll(list,"张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-111","张翠山-40","张良王-35","二麻子-37","谢广坤-38");
//只获取里面的年龄并打印
//第一个类型:流中原本的类型
//第二个类型:要转换后的类型
//apply的形参s:依次表示流里面的每一个数据
//返回值:表示转换后的数据
//map方法执行完毕后,流上的数据就变成了整数
//所有在下面forEach中,s依次表示流里面的每一个数据,这个数据现在就是整数
list.stream().map(newFunction<String, Integer>() {
@Override
publicIntegerapply(Strings) {
String[] arr=s.split("-");
StringageString=arr[1];
intage=Integer.parseInt(ageString);
returnage;
}
}).forEach(s->System.out.println(s));
list.stream()
.map(s->Integer.parseInt(s.split("-")[1]))
.forEach(s->System.out.println(s));
}
}
3.使用终结方法对流水线上的数据进行操作
名称 | 说明 |
void forEach(Consumer action) | 遍历 |
long count() | 统计 |
toArry() | 收集流中的数据,放到数组中 |
collect(Collector collector) | 收集流中的数据,放到集合中 |
packagecom.cjj.a01mystreamdemo01;
importjava.util.ArrayList;
importjava.util.Arrays;
importjava.util.Collections;
importjava.util.function.IntFunction;
publicclassStreamDemo09 {
publicstaticvoidmain(String[] args) {
/*
void forEach(Consumer action)遍历
long count()统计
toArry()收集流中的数据,放到数组中
collect(Collector collector) 收集流中的数据,放到集合中
*/
ArrayList<String>list=newArrayList<>();
Collections.addAll(list,"张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-111","张翠山-40","张良王-35","二麻子-37","谢广坤-38");
// void forEach(Consumer action)遍历
//Consumer的泛型:表示流中的数据类型
//accept方法的形参s:依次表示流里面的每一个数据
//方法体:对每一个数据的处理操作
/* list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});*/
//list.stream().forEach(s-> System.out.println(s));
//list.forEach(s-> System.out.println(s));
//long count()统计
//long count = list.stream().count();
//System.out.println(count);
//toArry()收集流中的数据,放到数组中
//Object[] arr1 = list.stream().toArray();
//System.out.println(Arrays.toString(arr1));
//InFunction的泛型:具体类型的数组
//apply的形参:流中数据的个数,要跟数组的长度保持一致
//apply的返回值:具体类型的数组
//toArray方法的参数的作用,负责创建一个指定类型的数组
//toArray方法的底层,会依次得到流里面的一个数据,并把数据放到数组里面
//toArray方法的返回值:是一个装着流里面所有数据的数组
/*String[] arr = list.toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
System.out.println(Arrays.toString(arr));*/
String[] arr=list.stream().toArray((Value) ->newString[Value]);
System.out.println(Arrays.toString(arr));
}
}
packagecom.cjj.a01mystreamdemo01;
importjava.util.*;
importjava.util.function.Function;
importjava.util.stream.Collectors;
publicclassStreamDemo010 {
publicstaticvoidmain(String[] args) {
/*
collect(Collector collector) 收集流中的数据,放到集合中(list Set Map)
注意点:
如果我们要收集到Map集合中,键不能重复,否则会报错
*/
ArrayList<String>list=newArrayList<>();
Collections.addAll(list,"张无忌-男-15","周芷若-女-14","赵敏-女-13","张强-男-20",
"张三丰-男-111","张翠山-那-40",
"张良王-男-35","二麻子-男-37","谢广坤-男-38");
//收集List集合当中
//需求:
//我要把所有男性收集起来
List<String>newList=list.stream()
.filter(s->"男".equals(s.split("-")[1]))
.collect(Collectors.toList());
System.out.println(newList);
//收集到Set
Set<String>newList2=list.stream()
.filter(s->"女".equals(s.split("-")[1]))
.collect(Collectors.toSet());
System.out.println(newList2);
//收集到Map集合中
//谁作为键,谁作为值
//把所有男性收集起来
//键:姓名 值:年龄
Map<String, Integer>map=list.stream()
.filter(s->"男".equals(s.split("-")[1]))
/*
toMap:参数1表示键的生成规则
参数2表示值的生成规则
参数1:
Function泛型1:表示流中的每一个数据类型
泛型2:表示Map集合中键的数据类型
方法apply形参:依次表示流里面的每一个数据
方法体:生成键的代码
返回值:已经生成的键
参数2:
Function泛型1:表示流中的每一个数据类型
泛型2:表示Map集合中值的数据类型
方法apply形参:依次表示流里面的每一个数据
方法体:生成值的代码
返回值:已经生成的值
*/
.collect(Collectors.toMap(newFunction<String, String>() {
@Override
publicStringapply(Strings) {
returns.split("-")[0];
}
},
newFunction<String, Integer>() {
@Override
publicIntegerapply(Strings) {
returnInteger.parseInt(s.split("-")[2]);
}
}));
System.out.println(map);
Map<String, Integer>map2=list.stream()
.filter(s->"男".equals(s.split("-")[1]))
.collect(Collectors.toMap(
s->s.split("-")[0],
s->Integer.parseInt(s.split("-")[2])));
System.out.println(map);
}
}
总结
1.Stream流的作用
结合了Lambda表达式,简化集合,数组的操作
2.Stream的使用步骤
获取Stream流对象
使用中间方法处理数据
使用终结方法
3.如何获取Stream流对象
单列集合:Collection中默认方法Stream
双列集合:不能直接获取
数组:Arrays工具类型中的静态方法stream
一堆零散的数据:Stream接口中的静态方法of
4.常见方法
中间方法:filter,limit,skip,distinct,concat,map
终结方法:forEach,count,collect
方法引用
把已经有的方法拿过来用,当作函数式接口中抽象方法的方法体
::是方法引用符号
方法引用 1.引用处需要是函数式接口 2.被引用的方法需要已经存在 3.被引用的方法的形参和返回值需要跟抽象方法的形参和返回值保持一致 4.被引用的方法的功能需要满足当前要求
packagecom.cjj.a01myfunction;
importjava.util.Arrays;
importjava.util.Comparator;
publicclassFunctionDemo01 {
publicstaticvoidmain(String[] args) {
//需求:创建一个数组,进行倒序排列
Integer[] arr= {3, 5, 4, 1, 6, 2};
//匿名内部类
Arrays.sort(arr, newComparator<Integer>() {
@Override
publicintcompare(Integero1, Integero2) {
returno2-o1;
}
});
//System.out.println(Arrays.toString(arr));
//lambda表达式
Arrays.sort(arr, (Integero1, Integero2) -> {
returno2-o1;
});
//lambda表达式简化格式
Arrays.sort(arr, (o1, o2) ->o2-o1);
//方法引用
//1.引用处需要是函数式接口
//2.被引用的方法需要已经存在
//3.被引用的方法的形参和返回值需要跟抽象方法的形参和返回值保持一致
//4.被引用的方法的功能需要满足当前要求
//表示引用FunctionDemo01类里面的subtraction方法
//把这个方法当做抽象方法的方法体
Arrays.sort(arr,FunctionDemo01::subtraction);//::是方法引用符号
System.out.println(Arrays.toString(arr));
}
//可以是java已经写好的,也可以是一些第三方工具类
publicstaticintsubtraction(intnum1, intnum2) {
returnnum2-num1;
}
}
方法引用的分类
1.引用静态方法
//格式: 类名::静态方法
//范例
Integer::parseInt
packagecom.cjj.a01myfunction;
importjava.util.ArrayList;
importjava.util.Arrays;
importjava.util.Collections;
importjava.util.function.Function;
publicclassFunctionDemo02 {
publicstaticvoidmain(String[] args) {
/*
方法引用
类::方法名
需求:
集合中有以下数组字,要求把他们变成int类型
"1","2","3","4","5"
*/
//1.创建集合添加元素
ArrayList<String>list=newArrayList<>();
Collections.addAll(list,"1","2","3","4","5");
/*//2.常规方法
ArrayList<Integer> list2 = new ArrayList<>();
for (String s : list) {
int i = Integer.parseInt(s);
list2.add(i);
}*/
/* //2.把他们变成int类型
list.stream().map(new Function<String,Integer>() {
@Override
public Integer apply(String s) {
int i = Integer.parseInt(s);
return i;
}
}).forEach(s-> System.out.println(s));*/
//3.方法引用简化
list.stream().map(Integer::parseInt).forEach(s->System.out.println(s));
}
}
2.引用成员方法
//格式:对象::成员方法
//其他类:其它类对象::方法名
//本类:this::方法名(引用处不能是静态方法)
//父类:super::方法名(引用处不能是静态方法)
1.引用其他类的成员方法
2.引用本类的成员方法
3.引用父类的成员方法
packagecom.cjj.a01myfunction;
publicclassStringOperation {
publicbooleanstringJudge(Strings){
returns.startsWith("张") &&s.length()==3;
}
}
packagecom.cjj.a01myfunction;
importjava.util.ArrayList;
importjava.util.Collections;
importjava.util.function.Predicate;
publicclassFunctionDemo03 {
publicstaticvoidmain(String[] args) {
/*
方法引用(引用成员方法)
格式:对象::成员方法
其他类:其它类对象::方法名
本类:this::方法名
父类:super::方法名
需求:
集合中有一些名字,按照要求过滤数据
数据:"张无忌","周芷若","赵敏","张强","张三丰"
要求:只要以张开头,而且名字是三个字的
*/
//1.创建集合
ArrayList<String>list=newArrayList<>();
//2.添加元素
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
//3.过滤数据
// list.stream().filter(s->s.startsWith("张")).filter(s->s.length()==3).forEach(s-> System.out.println(s));
/*list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张") && s.length()==3;
}
}).forEach(s-> System.out.println(s));*/
StringOperationso=newStringOperation();
list.stream().filter(so::stringJudge)
.forEach(s->System.out.println(s));
}
}
3.引用构造方法
//格式 :类名::new
//范例:
Student::new
packagecom.cjj.a01myfunction;
publicclassStudent {
privateStringname;
privateintage;
publicStudent() {
}
publicStudent(Stringstr) {
String[] arr=str.split("-");
this.name=arr[0];
this.age=Integer.parseInt(arr[1]);
}
publicStudent(Stringname, intage) {
this.name=name;
this.age=age;
}
/**
* 获取
* @return name
*/
publicStringgetName() {
returnname;
}
/**
* 设置
* @param name
*/
publicvoidsetName(Stringname) {
this.name=name;
}
/**
* 获取
* @return age
*/
publicintgetAge() {
returnage;
}
/**
* 设置
* @param age
*/
publicvoidsetAge(intage) {
this.age=age;
}
publicStringtoString() {
return"Student{name = "+name+", age = "+age+"}";
}
}
packagecom.cjj.a01myfunction;
importjava.util.ArrayList;
importjava.util.Collections;
importjava.util.List;
importjava.util.stream.Collectors;
publicclassFunctionDemo04 {
publicstaticvoidmain(String[] args) {
/*
格式 :类名::new
范例:
Student::new
目的:创建这个类的对象
需求:集合里面存储姓名和年龄,要求封装成Student对象并收集到List集合中
方法引用的规则:
1.引用处需要是函数式接口
2.被引用的方法需要已经存在
3.被引用的方法的形参和返回值需要跟抽象方法的形参和返回值保持一致
4.被引用的方法的功能需要满足当前要求
*/
//1.创建集合对象
ArrayList<String>list=newArrayList<>();
//2.添加数据
Collections.addAll(list,"张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-111","张翠山-40",
"张良王-35","二麻子-37","谢广坤-38");
//3.封装成Student对象并收集到List集合中
/*List<Student> newList = list.stream().map(new Function<String, Student>() {
@Override
public Student apply(String s) {
String[] arr = s.split("-");
String name = arr[0];
int age = Integer.parseInt(arr[1]);
return new Student(name, age);
}
}).collect(Collectors.toList());
System.out.println(newList);*/
List<Student>collect=list.stream().map(Student::new).collect(Collectors.toList());
System.out.println(collect);
}
}
其他调用方法
1.使用类名引用成员方法
//格式:类名::成成员方法
//范例
String::substring
packagecom.cjj.a01myfunction;
importjava.util.ArrayList;
importjava.util.Collections;
importjava.util.function.Function;
publicclassFunctionDemo05 {
publicstaticvoidmain(String[] args) {
/*
//格式:类名::成成员方法
范例
String::substring
方法引用的规则:
1.引用处需要是函数式接口
2.被引用的方法需要已经存在
3.被引用的方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值保持一致
4.被引用的方法的功能需要满足当前要求
抽象方法形参的详解
第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法
在Stream流当中。第一个参数一般都表示流里面的每一个数据
假设流里面的数据是字符串,那么使用这种方法进行方法调用,只能引用String这个类的方法
第二个形参到最后一个形参保持一致:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要无参的成员方法
局限性:
不能引用所有类中的成员方法。
是跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法
需求:
集合里面一下字符串,要求变成大写进行输出
*/
//1.创建集合
ArrayList<String>list=newArrayList<>();
//2.添加数据
Collections.addAll(list,"aaa","bbb","ccc","ddd");
//3.变成大写进行输出
/* list.stream().map(new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
}).forEach(s-> System.out.println(s));*/
//拿着流里面的每一个数据,去调用String类中的toUpperCase方法,方法的返回值就是转换后的结果
list.stream().map(String::toUpperCase).forEach(s->System.out.println(s));
}
}
2.引用数组构造方法
//格式:数据类型[]::new
//范例:
int[]::new
packagecom.cjj.a01myfunction;
importjava.util.ArrayList;
importjava.util.Arrays;
importjava.util.Collections;
importjava.util.concurrent.Callable;
importjava.util.function.IntFunction;
publicclassFunctionDemo06 {
publicstaticvoidmain(String[] args) {
/*
格式:数据类型[]::new
范例:
int[]::new
目的:
创建一个指定类型的数组
需求:
集合中存储一些整数,收集到数组当中
细节:
数组的类型,需要跟流中的数据的类型保持一致
*/
//1.创建集合并添加元素
ArrayList<Integer>list=newArrayList<>();
Collections.addAll(list,1,2,3,4,5);
/* //2.收集到数组中
Integer[] arr = list.stream().toArray(new IntFunction<Integer[]>() {
@Override
public Integer[] apply(int value) {
return new Integer[value];
}
});
//3.打印
System.out.println(Arrays.toString(arr));*/
Integer[] arr1=list.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(arr1));
}
}
总结
1.什么是方法引用?
把已经有的方法拿过来用,当作函数式接口中抽象方法的方法体
2.::是什么符号
方法引用符号
3.方法引用时需要注意什么?
1.引用处需要是函数式接口 2.被引用的方法需要已经存在 3.被引用的方法的形参和返回值需要跟抽象方法的形参和返回值保持一致 4.被引用的方法的功能需要满足当前要求
格式:
1.引用静态方法
类名::静态方法
2.引用成员方法
对象::成员方法
this::成员方法
super::成员方法
3.引用构造方法
类名::new
4.使用类名引用成员方法
类名::成员方法
5.引用数组的构造方法
数据类型[] ::new