一、Collection(单列集合)
1、Collection接口的体系框架
List系列集合:添加的元素是有序、可重复、有索引
Set系列集合:添加的元素是无序、不重复、无索引
2、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() | 返回集合中元素的个数/集合的长度 |
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo2 {
/*
* | 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是一个接口,我们不能直接创建它的对象。因此,现在我们学习它的方法时,只能创建它实现类的对象。
* 实现类:ArrayList
* */
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>();
//1、添加元素
//细节1:如果我们要往List系列集合中添加数据,那么方法永远返回true,因为List系列的是允许元素重复的。
//细节2:如果我们往Set系列集合中添加数据,如果当前添加元素不存在,方法返回true,表示添加成功。
// 如果当前要添加的元素已经存在,方法返回false,表示添加失败。
// 因为Set系列集合不允许重复
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
System.out.println(coll);
//3.删除
//细节1:因为Collection里面定义的是共性的方法,所以此时不能通过索引进行删除。只能通过元素的对象进行删除。
//细节2:方法会有一个布尔类型的返回值,删除成功返回true,删除失败返回false.如果要删除的元素不存在,就会删除失败
coll.remove("aaa");
System.out.println(coll);
//4.判断元素是否包含
//细节:底层是依赖equals方法进行判断是否存在。
//所以,如果集合中存储的是自定义对象,也是通过contains方法来判断是否包含,那么javabean类中,一定要重写equals方法
boolean contains = coll.contains("aaa");
System.out.println(contains);
//5.判断集合是否为空
boolean empty1 = coll.isEmpty();
System.out.println(empty1);
//6.获取集合长度
int size = coll.size();
System.out.println(size);
//2.清空
coll.clear();
System.out.println(coll);
//5.判断集合是否为空
boolean empty = coll.isEmpty();
System.out.println(empty);
}
}
运行结果:
[aaa, bbb, ccc]
[bbb, ccc]
false
false
2
[]
true
public boolean contains(Object obj)中的细节:
底层是依赖equals方法进行判断是否存在。
import com.collection.exer.collection.bean.Student;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo3 {
public static void main(String[] args) {
//1.创建集合的对象
Collection<Student> coll = new ArrayList<>();
//2.创建三个学生对象
Student s1 = new Student("张三", 23);
Student s2 = new Student("李四", 24);
Student s3 = new Student("王五", 26);
//将学生对象添加到集合当中
coll.add(s1);
coll.add(s2);
coll.add(s3);
//判断集合中某一个学生对象是否包含
Student s4 = new Student("张三", 23);
//因为contains方法在底层依赖equals方法判断对象是否一致的
//如果存在自定义对象,没有重写equals方法,那么默认使用Object类中的equals方法进行判断,而Object类中equals方法,依赖地址值进行判断。
//需求:如果同名和同年龄,就认为是同一学生
//所以,需要在自定义的javaBean类中,重写equals方法就可以了
System.out.println(coll.contains(s4));
}
}
Student类
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
3、Collection系列集合的三种通用遍历的方式
之前的for循环遍历只有List的子类可以进行遍历,因为有索引,但Set的子类没有索引,因此采用以下几种通用遍历方式。
(1)、迭代器遍历
迭代器不依赖索引。迭代器在java中的类是Iterator,迭代器是集合专用的变量方式。在遍历的过程中需要删除元素,请使用迭代器。
Collection集合获取迭代器
方法名称 | 说明 |
---|---|
Iterator<E> iterator | 返回迭代器对象,默认指向当前集合的0索引 |
Iterator中常用的方法
方法名 | 说明 |
---|---|
boolean hasNext() | 判断当前位置是否有元素,有元素返回true,没有元素返回false |
E next() | 获取当前位置的元素,并将迭代器对象移向下一个位置 |
default void remove() | 从底层集合中删除此迭代器返回的最后一个元素 |
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo2 {
/*
* Collection系列集合的三种通用的遍历方式:
* 1、迭代器遍历
* 2、增强for遍历
* 3、lambda表达式遍历
*
*迭代器遍历的三个方法:
* Iterator<E> iterator() :获取一个迭代器对象
* boolean hasNext() :判断当前指向位置是否有元素
* E next() :获取当前位置指向的元素并移动到下一位置
* */
public static void main(String[] args) {
//1、创建集合并添加元素
Collection<String> c1 = new ArrayList<>();
c1.add("张三1");
c1.add("张三2");
c1.add("张三3");
c1.add("张三4");
c1.add("张三5");
System.out.println(c1);
//2.获取迭代器对象
//通过Iterator迭代遍历集合
Iterator iterator = c1.iterator();
//3.利用循环不断去获取集合中的每一个元素
while (iterator.hasNext()){//判断是否为下一个元素
//条件成立 获取下一个元素 并移动游标位置
//4.next方法的两件事情:获取元素并移动指针
Object next = iterator.next();
System.out.println(next);
}
}
}
细节注意点:
1、如果迭代器已经指向了集合的末端,没有元素了,再强行的调用next()方法获取元素,那么就会报错NoSuchElementException.
2、迭代器遍历完毕,指针不会复位
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo2 {
/*
* Collection系列集合的三种通用的遍历方式:
* 1、迭代器遍历
* 2、增强for遍历
* 3、lambda表达式遍历
*
*迭代器遍历的三个方法:
* Iterator<E> iterator() :获取一个迭代器对象
* boolean hasNext() :判断当前指向位置是否有元素
* E next() :获取当前位置指向的元素并移动到下一位置
* */
public static void main(String[] args) {
//1、创建集合并添加元素
Collection<String> c1 = new ArrayList<>();
c1.add("张三1");
c1.add("张三2");
c1.add("张三3");
c1.add("张三4");
c1.add("张三5");
System.out.println(c1);
//2.获取迭代器对象
//通过Iterator迭代遍历集合
Iterator iterator = c1.iterator();
//3.利用循环不断去获取集合中的每一个元素
while (iterator.hasNext()){//判断是否为下一个元素
//条件成立 获取下一个元素 并移动游标位置
//4.next方法的两件事情:获取元素并移动指针
Object next = iterator.next();
System.out.println(next);
}
//当上面循环结束之后,迭代器的指针已经指向了最后没有元素的位置
//System.out.println(iterator.next());//NoSuchElementException
//迭代器遍历完毕,指针不会复位
System.out.println(iterator.hasNext());
//如果我们要继续第二次遍历,只能再次获取一个迭代器对象
Iterator<String> it = c1.iterator();
while (it.hasNext()){
String s = it.next();
System.out.println(s);
}
}
}
3、循环中只能用一次next方法
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo4 {
/*
* Collection系列集合的三种通用的遍历方式:
* 1、迭代器遍历
* 2、增强for遍历
* 3、lambda表达式遍历
*
*迭代器遍历的三个方法:
* Iterator<E> iterator() :获取一个迭代器对象
* boolean hasNext() :判断当前指向位置是否有元素
* E next() :获取当前位置指向的元素并移动到下一位置
*
* 迭代器的细节注意点:
* 1、报错NoSuchElementException
* 2、迭代器遍历完毕,指针不会复位
* 3、循环中只能用一次next方法
* 4、迭代器遍历时,不能用集合的方法进行增加或删除
* */
public static void main(String[] args) {
//1、创建集合并添加元素
Collection<String> c1 = new ArrayList<>();
c1.add("张三1");
c1.add("张三2");
c1.add("张三3");
c1.add("张三4");
c1.add("张三5");
System.out.println(c1);
//2.获取迭代器对象
//通过Iterator迭代遍历集合
Iterator iterator = c1.iterator();
//3.利用循环不断去获取集合中的每一个元素
while (iterator.hasNext()){//判断是否为下一个元素
//条件成立 获取下一个元素 并移动游标位置
//4.next方法的两件事情:获取元素并移动指针
System.out.println(iterator.next());//张三1 张三3 张三5
System.out.println(iterator.next());//张三2 张三4 NoSuchElementException
}
}
}
4、迭代器遍历时,不能用集合的方法进行增加或删除
暂时当作一个结论先行记忆,在今天我们会讲解源码详细的再来分析 如果实在要删除;那么可以用迭代器提供的remove方法进行删除。 如果要添加,暂时没有办法。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo5 {
/*
* Collection系列集合的三种通用的遍历方式:
* 1、迭代器遍历
* 2、增强for遍历
* 3、lambda表达式遍历
*
*迭代器遍历的三个方法:
* Iterator<E> iterator() :获取一个迭代器对象
* boolean hasNext() :判断当前指向位置是否有元素
* E next() :获取当前位置指向的元素并移动到下一位置
*
* 迭代器的细节注意点:
* 1、报错NoSuchElementException
* 2、迭代器遍历完毕,指针不会复位
* 3、循环中只能用一次next方法
* 4、迭代器遍历时,不能用集合的方法进行增加或删除
* 暂时当作一个结论先行记忆,在今天我们会讲解源码详细的再来分析
* 如果实在要删除;那么可以用迭代器提供的remove方法进行删除。
* 如果要添加,暂时没有办法。
* */
public static void main(String[] args) {
//1、创建集合并添加元素
Collection<String> c1 = new ArrayList<>();
c1.add("张三1");
c1.add("张三2");
c1.add("张三3");
c1.add("张三4");
c1.add("张三5");
System.out.println(c1);
//2.获取迭代器对象
//通过Iterator迭代遍历集合
Iterator<String> it = c1.iterator();
//3.利用循环不断去获取集合中的每一个元素
while (it.hasNext()){//判断是否为下一个元素
//条件成立 获取下一个元素 并移动游标位置
//4.next方法的两件事情:获取元素并移动指针
String str = it.next();//ConcurrentModificationException 并发修改异常
if (str.equals("张三2")) {
it.remove();
}
}
System.out.println(c1);
}
}
(2)、增强for遍历
增强for的底层就是迭代器,为了简化迭代器的代码书写。它是JDK5以后出现的,其内部原理就是一个Iterator迭代器,所有的单列集合和数组才能用增强for进行遍历。
格式:
for(元素的数据类型 变量名:数组或集合){
}
增强for的细节
修改增强for中的变量,不会改变集合中原本的数据。
import java.util.ArrayList;
import java.util.Collection;
public class ForEachDemo2 {
/*
* Collection系列集合的三种通用的遍历方式:
* 1、迭代器遍历
* 2、增强for遍历
* 3、lambda表达式遍历
*
* 增强for格式:
* for(数据类型 变量名:集合/数组){
*
* }
* 快速生成方式:
* 集合名字+for 回车
* */
public static void main(String[] args) {
Collection<String> c1 = new ArrayList();
c1.add("张三1");
c1.add("张三2");
c1.add("张三3");
c1.add("张三4");
c1.add("张三5");
System.out.println(c1);
//通过foreach循环来实现遍历
//注意点:
//str其实就是一个第三方变量,在循环的过程中依次表示集合中的每一个数据
for (String str:c1) {
str = "qqqq";//str第三方变量,集合中的数据不会改变
}
System.out.println(c1);
}
}
(3)、Lamdba表达式遍历
得益于JDK8开始的新技术Lambda表达式,提供了一种更简单、更直接的遍历集合的方式。
方法名称 | 说明 |
---|---|
default void forEach(Consumer<? super T> action): | 结合lambda遍历集合 |
匿名内部类(匿名内部类的对象 )
格式:
new 类名或者接口名(){
重写方法;
}
创建并继承或实现 某类或某接口
Lambda表达式的标准格式
Lambda表达式是JDK8开始后的一种新语法形式。
()->{
}
() 对应着方法的形参
-> 固定格式
{} 对应方法的方法体
注意点:
Lambda表达式可以用来简化匿名内部类的书写
Lambda表达式只能简化函数式接口的匿名内部类的写法
函数式接口:有且仅有一个抽象方法的接口叫做函数式接口,接口上方可以加@FunctionalInterface注解
利用匿名内部类的形式去调用下面的方法
调用一个方法的时候,如果方法的形参是一个接口,那么我们要传递这个接口的实现类对象
如果实现类对象只要用到一次,就可以用匿名内部类的形式进行书写
二、List系列集合
1、List集合的特点
有序:存和取的元素顺序一致
有索引:可以通过索引操作元素
可重复:存储的元素可以重复
2、List集合的特有方法
Collection的方法List都继承了
List集合因为有索引,所以多了很多索引操作的方法。
方法名称 | 说明 |
---|---|
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
import java.util.ArrayList;
import java.util.List;
public class ListDemo1 {
public static void main(String[] args) {
/*
* | void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
* | ----------------------------- | -------------------------------------- |
* | E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
* | E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
* | E get(int index) | 返回指定索引处的元素 |
* */
//1.创建集合
List<String> list = new ArrayList<>();
//2.添加元素
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
list.add("eee");
System.out.println("原集合中的元素"+list);
//void add(int index,E element) | 在此集合中的指定位置插入指定的元素
list.add(3,"QQQ");
System.out.println("添加元素之后的集合元素"+list);
//E remove(int index) | 删除指定索引处的元素,返回被删除的元素
list.remove(1);
System.out.println("删除索引为1的元素之后的集合元素"+list);
//E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素
String set = list.set(4, "MMMM");
System.out.println("修改的元素为"+set);
System.out.println("修改之后的集合元素"+list);
String s = list.get(3);
System.out.println("集合中获取到的元素:"+s);
System.out.println(list);
}
}
注意:删除的特有细节
import java.util.ArrayList;
import java.util.List;
public class ListDemo2 {
public static void main(String[] args) {
/*
* List系列集合中的两个删除的方法
* 1、直接删除元素
* 2、通过索引进行删除 |
* */
//1.创建集合并添加元素
List<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(2);
integers.add(3);
integers.add(4);
integers.add(5);
//2.删除元素
//请问:此时删除的是1这个元素,还是1索引上的元素?
//为什么?
//因为在调用方法的时候,如果方法出现了重载现象
//优先调用,实参跟形参类型一致的那个方法。
integers.remove(1);
//手动装箱,手动把基本数据类型的1,变成Integer类型
Integer i = Integer.valueOf(1);
integers.remove(i);
System.out.println(integers);
}
}
3、List集合的五种遍历方式
(1)、迭代器遍历
(2)、列表迭代器遍历
(3)、增强for遍历
(4)、Lambda表达式
(5)、普通for循环遍历
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.function.Consumer;
public class ListDemo3 {
/*
List循环遍历的五种遍历方式:
* (1)、迭代器遍历
* (2)、列表迭代器遍历
* (3)、增强for遍历
* (4)、Lambda表达式
* (5)、普通for循环遍历
*
* */
public static void main(String[] args) {
//创建结合并添加元素
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
list.add("eee");
//1、迭代器遍历
//通过list.iterator获取迭代器对象
System.out.println("迭代器遍历结果为:");
Iterator<String> it = list.iterator();
while (it.hasNext()){
String nextStr = it.next();
System.out.println(nextStr);
}
//2.增强for循环遍历
//下面的变量s,其实就是一个第三方的变量。
//在循环的过程中,依次表示集合中的每一个元素
System.out.println("通过增强for循环遍历的集合:");
for (String forStr : list) {
System.out.println(forStr);
}
//3.Lambda表达式
//forEach方法的底层其实就是一个遍历,依次得到集合中的每一个元素
//并把每一个元素传递给下面的accept方法
//accept方法的形参s,依次表示集合中的每一个元素
System.out.println("内部类的方式:");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
System.out.println("Lambda表达式:");
list.forEach(s -> System.out.println(s));
//4.普通for进行遍历
//size方法跟get方法还有循环结合的方式,利用索引获取到集合中的每一个元素
System.out.println("通过普通for循环进行遍历:");
for (int i = 0; i < list.size(); i++) {
//i:依次表示集合中的每一个索引
String s = list.get(i);
System.out.println(s);
}
//5.列表迭代器
//获取列表迭代器的对象,里面的指针也是默认也是指向0索引的
//额外添加了一个方法:在遍历过程中,可以添加元素
ListIterator<String> strList = list.listIterator();
while (strList.hasNext()){
String str = strList.next();
if (str.equals("bbb")) {
strList.add("QQQ");
}
}
System.out.println(list);
}
}
4、五种遍历方式对比
遍历名称 | 需求 |
---|---|
迭代器遍历 | 在遍历的过程中需要删除元素,请使用迭代器。 |
列表迭代器 | 在遍历的过程中需要添加元素,请使用列表迭代器。 |
增强for遍历/Lambda表达式 | 仅仅想遍历,那么使用增强for或Lambda表达式。 |
普通for | 如果遍历的时候像操作索引,可以用普通for。 |
(一)、数据结构(栈、队列、数组、链表)
1、数据结构概述
数据结构是计算机底层存储,组织数据的方式。
是指数据相互之间是以什么方式排列在一起的。
数据结构是为了更加方便的管理和使用数据,需要结合具体业务场景来进行选择。
一般情况下,精心选择的数据结构可以带来更高的运行或存储效率。
2、常见的数据结构
栈、队列、数组、链表、二叉树、二叉查找树、平衡二叉树、红黑树
(1)、栈
特点:后进先出,先进后出
数据进入到栈模型的过程称为:压/进栈
数据离开栈模型的过程称为:弹/出栈
(2)、队列
特点:先进先出,后进后出
数据从后端进入队列模型的过程称为:入队列
数据从前端离开队列模型的过程称为:出队列
(3)、数组
特点(查询快,增删慢):
查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相同。(元素在内存中是连续存储的)
删除效率低:要将原始数据删除,同时后面每个数据前移。
添加效率极低:添加位置后的每个元素后移,再添加元素。
(4)、链表
结点:链表中的每一个元素称之为结点。
特点(查询慢,增删快):
链表中的结点是独立的对象,在内存中不是连续的,每个结点包含数据值和下一个结点的地址。
增删相对较快
(二)、ArrayList集合
ArrayList集合底层原理
(1)、利用空参创建的集合,在底层创建一个默认长度为0的数组(elementData)
(2)、添加第一个元素时,底层会创建一个新的长度为10的数组(size表示集合元素的个数,也表示下次存入位置)
(3)、存满时,会扩容为原来的1.5倍
(4)、如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准
(三)、LinkedList集合
特有方法 | 说明 |
---|---|
public void addFirst(E e) | 在该列开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFrist() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
LinkedList集合底层原理
底层数据结构是双链表,查询慢,增删快,但是如果操作的是首尾元素,速度也是极好的。
如何避免并发修改异常
在使用迭代器或者增强for遍历集合的过程中,不要使用集合的方法去添加或删除元素即可
(四)、泛型深入
1、泛型
是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。
泛型的格式:<数据类型>
注意:泛型只能支持引用数据类型
没有泛型的时候,集合如何存储数据?
如果没有给集合指定类型,默认认为所有的数据类型都是Object类型,此时可以往集合添加任意的数据类型。
带来一个坏处:我们在获取数据的时候,无法使用其特有行为。
泛型可以在添加数据的时候就把类型进行统一,而且在获取数据时,也可以省略强转了,非常方便
泛型的好处:
统一数据类型
把运行时期的问题提前到了编译期间,避免了强制转换可能出现的异常,因为在编译阶段就能确定下来。
扩展知识点:Java中的泛型是伪泛型
泛型的细节:
-
泛型中不能写基本数据类型
-
指定泛型的具体类型后,传递数据时,可以传入该类型或者其子类型
-
如果不写泛型,类型默认时Object
2、泛型类(类后面)
使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
格式:
修饰符 class 类名<类型>{
}
类型中可以写成:T、E、K、V等。类型可以理解为变量,但是不是用来记录是数据的,而是记录数据的类型
import java.util.Arrays;
public class MyArrayList<E> {
/*
* 当编写一个类时,如果不确定类型,那么这个类就可以定义为泛型类。
* */
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);
}
}
3、泛型方法(方法上面)
方法中形参类型不确定时,可以使用类名后面定义的泛型<E>(所有方法都能使用),也可以在方法申明上定义自己的泛型(只能本方法能使用)。
格式:
修饰符 <类型> 返回值类型 方法名(类型 变量名){
}
注意:类型可以了理解为变量,但是不是用来记录数据的,而是记录类型的,可以写成:T、E、K、V等
import java.util.ArrayList;
public class ListUtil { private ListUtil(){}
/*
* 类中定义一个静态方法addAll,用来添加多个集合的元素。
* */
/*
* 参数一:集合
* 参数二:最后要添加的元素
* */
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);
}
/*public static<E> void addAll1(ArrayList<E> list,E...e){
for (E element : e){
list.add(element);
}
}*/
public void show(){
System.out.println("最爱吃兽奶!!!!");
}
}
4、泛型接口(接口后面)
格式:
修饰符 interface 接口名<类型>{
}
重点:
如何使用带泛型的接口
方式1:实现类给出具体类型
方式2:实现类延续泛型,创建对象时再确定类型
5、泛型的继承和通配符
泛型不具备继承性,但是数据具备继承性
泛型的通配符:
?也表示不确定类型,它可以进行类型的限定
?extends E: 表示可以传递E或者E所有的子类类型
?super E:表示可以传递E或E所以的父类类型
应用场景:
如果我们定义的类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。
如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以使用泛型的通配符
泛型的通配符:
关键点:可以限定类型的范围。
import java.util.ArrayList;
public class GenericsDemo4 {
public static void main(String[] args) {
/*
*泛型不具备继承性,但是数据具备继承性
* */
//创建集合的对象
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();
//调用method方法
//method(list1);
//method(list2);
//method(list3);
list1.add(new Fu());
list1.add(new Ye());
list1.add(new Zi());
}
/*
* 此时,泛型里面写的是什么类型,那么只能传递什么类型的数据。
* */
public static void method(ArrayList<Ye> list){
}
}
class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}
package com.collection.exer.collection.mylist;
import java.util.ArrayList;
public class GenericsDemo5 {
public static void main(String[] args) {
/*
*需求:
* 定义一个方法,形参是一个集合,但是集合中的数据类型不确定。
* */
//创建集合的对象
ArrayList<Ye1> list1 = new ArrayList<>();
ArrayList<Fu1> list2 = new ArrayList<>();
ArrayList<Zi1> list3 = new ArrayList<>();
ArrayList<Student> list4 = new ArrayList<>();
//调用method方法
method(list1);
method(list2);
method(list3);
//method(list4);
list1.add(new Fu1());
list1.add(new Ye1());
list1.add(new Zi1());
}
/*
* 此时,泛型里面写的是什么类型,那么只能传递什么类型的数据。
* 弊端:
* 利用泛型方法有一个小弊端,此时它可以接收任意数据类型
* 希望:本方法虽然不确定数据类型,但是以后我希望只能传递Ye Fu Zi
*
* 此时我们就可以使用泛型的通配符:
* ?也表示不确定的类型
* 它可以进行类型限定
* ? extends E:表示可以传递E或者E所有的子类类型
* ? super E:表示可以传递E或着E所有的父类类型
* */
public static void method(ArrayList<? extends Ye1> list){
}
}
class Ye1{}
class Fu1 extends Ye1{}
class Zi1 extends Fu1{}
class Student{}
(五)、数据结构(二叉树、二叉查找树、平衡二叉树)
1、树
度:每一个结点子节点的数量
二叉树:任意结点的度<=2
树高:树的总层数
根节点:最顶端的结点
左子结点:左下方的结点
右子结点:右下方的结点
2、二叉查找树(又称二叉排序树或者二叉搜索树)
特点:
每一个结点上最多有两个子节点
任意结点左子树上的值都小于当前结点
任意结点右子树上的值都大于当前结点
添加结点规则:
小的存在左边
大得存在右边
一样的不存
查找结点:
查找慢,效率低
首先先跟根节点进行比较,再跟其子节点进行比较
二叉查找树的遍历
前序遍历:从根节点开始,然后按照根节点,左子节点,右子节点的顺序遍历
遍历顺序为:20->18->16->19->23->22->24
中序遍历:从最左边的子节点开始,然后按照左子节点,根节点,右子节点的顺序
遍历顺序为:16->18->19->20->22->23->24
后序遍历:从最左边的子节点开始,然后按照左子节点,右子节点,根节点的顺序遍历
遍历顺序为:16->19->18->22->24->23->20
层序遍历:从根节点开始一层一层的遍历
遍历顺序为:20->18->23->16->19->22->24
二叉查找树弊端
如果二叉树出现子树高度差较大的这种树,二叉查找树查找效率会降低
3、平衡二叉树
规则:以二叉查找树为基础,任意节点左右左子树高度差不超过1
平衡机制:通过旋转机制保持平衡。
规则1:左旋
确定指点:从添加的节点开始,不断的往父节点找不平衡的节点
步骤:以不平衡的点作为支点
把指点左旋降级,变成左子节点
如果原先的右子节点没有左子节点,晋升原来的右子节点变成父节点;如果原先的右子节点有左子节点,原先 的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点
规则2:右旋
确定指点:从添加的节点开始,不断的往父节点找不平衡的节点
步骤:以不平衡的点作为支点
把指点右旋降级,变成右子节点
如果原先的左子节点没有右子节点,晋升原来的左子节点变成父节点;如果原先的左子节点有右子节点,原先 的左子节点变成新的父节点,并把多余的右子节点出让,给已经降级的根节点当右子节点
触发机制:当添加一个节点之后,该树不再是一颗平衡二叉树
数据结构(平衡二叉树)需要旋转的四种情况
左左:当根节点左子树的左子树有节点插入,导致二叉树不平衡(一次右旋)
左右:当根节点左子树的右子树有节点插入,导致二叉树不平衡(先局部左旋,再整体一次右旋)
右右:当根节点右子树的右子树有节点插入,导致二叉树不平衡(一次左旋)
右左:当根节点左子树的左子树有节点插入,导致二叉树不平衡(先局部右旋,再整体一次左旋)
4、树的演变
(六)、数据结构(红黑树)
-
红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构。
-
1972年初出现,当时被称之为平衡二叉树B树。后来,1978年被修改为如今的“红黑树”。
-
它是一种特殊的二叉树,红黑树的每一个节点上都有存储位表示节点的颜色,
-
每个节点可以是红或者黑;红黑树不是高度平衡的,它的平衡是通过“红黑规则”进行实现的
-
红黑树增删改查的性能都很好
平衡二叉树与红黑树的比较
平衡二叉树:
高度平衡
当左右子树高度差超过1小时,通过旋转保持平衡
红黑树:
是一个二叉查找树
但是不是高度平衡的
条件:特有的红黑规则
红黑规则
1、每个节点或是红色的,或者是黑色的
2、根节点必须是黑色的
3、如果一个节点没有子节点或者父节点,则该节点相应的指针属性位Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
4、如果某一个节点是红色的,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
5、对每一个节点,从该节点到其所有的后代叶节点的简单路径上,均包含相同数目的黑色节点;
添加节点规则
默认颜色:添加节点默认是红色的(效率高)
调整方案
二、Set系列集合
特点:
-
添加的元素是无序、不重复、无索引
-
Set接口中的方法上基本上与Collection的API一致。
无序:存取顺序不一致
不重复:可以去除重复
无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素
Set集合实现类
HashSet:无序、不重复、无索引
LinkedHashSet:有序、不重复、无索引
TreeSet:可排序、不重复、无索引
(一)、HashSet
HashSet底层原理
HashSet集合底层采用哈希表存储数据
哈希表是一种对于增删查改数据性能都较好的结构
哈希表组成
JDK8之前:数组+链表
JDK8开始:数组+链表+红黑树
哈希值:对象的整数表现形式
根据hashCode方法算出来的int类型的整数
该方法定义在Object类中,所有的对象都可以调用,默认使用地址值进行计算
一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值
对象的哈希值特点
如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
如果已经重写hashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)
HashSet JDk8以前底层原理
(1)、创建一个默认长度16,默认加载因子0.75的数组,数组名table(加载因子实质为HashSet扩容时机,当数组 里面存了16*0.75 = 12的时候,数组就会扩容到元素组的2倍)
(2)、根据元素的哈希值跟数组的长度计 算出应存入的位置
int index = (数组长度-1) & 哈希值
(3)、判断当前位置是否为null,如果是null直接存入;如果位置不为null,表示有元素,则调用eqauls方法比较属性 值。
(4)、一样:不存 不一样:存入数组,形成链表
JDK8以前:新元素存入数组,老元素挂在新元素下面
JDK8以后:新元素直接挂在老元素下面,当链表长度超过8,而且数组长度大于等于64时,自动转换为红黑 树。
如果集合中存储的是自定义对象,必须要重写hashCode和equals方法。(重写hashCode的目的根据其属性值 计算哈希值)
HashSet的三个问题
HashSet为什么存和取的顺序不一样?
HashSet为什么没有索引?
Hash是利用什么机制保证数据去重的
(二)、LinkedHashSet
LinkedHashSet底层原理
有序、不重复、无索引
这里的有序指的是保证存储和取出的元素顺序一致
原理:底层数据结构依然是哈希表,只是每个元素又额外的多了一个双链表机制记录存储的顺序。
(三)、TreeSet
特点:
不重复、无索引、可排序
可排序:按照元素的默认规则(由小到大)排序。
TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能较好。
TreeSet集合默认的规则
对于数值类型:Integer,Double,默认按照从小到大的顺序进行排序。
对于字符、字符串类型:按照字符在ASCII码表中的数字升序进行排序。
TreeSet的两种比较方式
默认排序/自然排序:Javabean类实现Comparable接口指定比较规则
public class Student implements Comparable<Student>{
/*
* 需求:创建TreeSet集合,并添加3个学生对象,要求按照年龄进行排序
* */
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
@Override
public int compareTo(Student o) {
//指定排序规则
//只看年龄,想要年龄的升序进行排序
return this.getAge() - o.getAge();
//this:表示当前要添加的元素
//o:表示已经在红黑树存在的元素
//返回值:
//负数:认为要添加的元素是小的,存左边
//正数:认为要添加的元素是大的,存右边
//0:认为要添加的元素已经存在,舍弃
}
}
import com.collection.exer.collection.bean.Student;
import java.util.TreeSet;
public class TreeSetDemo1 {
public static void main(String[] args) {
Student s1 = new Student("张三", 23);
Student s2 = new Student("李四", 18);
Student s3 = new Student("王五", 34);
TreeSet<Student> students = new TreeSet<>();
students.add(s1);
students.add(s2);
students.add(s3);
System.out.println(students);
}
}
运行结果:
[Student{name = 李四, age = 18}, Student{name = 张三, age = 23}, Student{name = 王五, age = 34}]
比较器排序:创建TreeSet集合时,自定义Comparator比较器对象,指定比较规则
public class Student{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo2 {
/*
* 需求:请自行选择比较器排序和自然排序两种方式:
* 要求:存入五个字符串,"c","ab","ef","qwer","acer"
* */
public static void main(String[] args) {
TreeSet<String> strings = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//按长度进行排序 ctrl + p
int i = o1.length() - o2.length();
return i == 0 ? o1.compareTo(o2) : i;//如果i=0,那么就用原来的比较方式进行比较。
}
});
strings.add("c");
strings.add("ab");
strings.add("ef");
strings.add("qwer");
strings.add("acer");
System.out.println(strings);
}
}
运行结果:
[c, ab, ef, acer, qwer]
如果两种方式同时存在以方式二比较器排序为准。
二、Map(双列集合)
双列集合的特点
(1)、双列集合一次需要存一对数据,分别为键和值
(2)、键不能重复,值可以重复
(3)、键和值是一一对应的,每一个键只能找到自己对应的值
(4)、键+值这个整体 我们称之为”键值对“或者”键值对对象“,在Java中叫做”Entry对象“
双列集合的体系结构
Map的常见API
Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的
方法名称 | 说明 |
---|---|
V put(K key,V value) | 添加元素。在添加元素的时候,如果键不存在,那么直接把键值对对象添加到map集合中。如果键存在,那么会将原有的键值对对象覆盖,会把被覆盖的值进行返回 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合键值对的个数 |
import java.util.HashMap;
import java.util.Map;
public class MyMapDemo {
/*
* | V put(K key,V value) | 添加元素 |
* | ----------------------------------- | ---------------------------------- |
* | V remove(Object key) | 根据键删除键值对元素 |
* | void clear() | 移除所有的键值对元素 |
* | boolean containsKey(Object key) | 判断集合是否包含指定的键 |
* | boolean containsValue(Object value) | 判断集合是否包含指定的值 |
* | boolean isEmpty() | 判断集合是否为空 |
* | int size() | 集合的长度,也就是集合键值对的个数 |
*
* */
public static void main(String[] args) {
//创建Map集合的对象
Map<String, String> m = new HashMap<>();
//添加元素
//put方法的细节:
//添加/覆盖
//在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合中
//在添加数据的时候哦,如果键存在,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回。
m.put("郭靖", "黄蓉");
m.put("韦小宝", "沐剑屏");
m.put("尹志平", "小龙女");
//String put = m.put("韦小宝", "双儿");
//System.out.println(put);//沐剑屏
//删除
//String re = m.remove("郭靖");
//System.out.println(re);//黄蓉
//清空集合
//m.clear();
//判断是否包含
/*
boolean keyResult = m.containsKey("郭靖");
System.out.println(keyResult);//true
boolean valueResult = m.containsValue("小龙女");
System.out.println(valueResult);//true
*/
//判断集合是否为空
boolean empty = m.isEmpty();
System.out.println(empty);//false
int size = m.size();
System.out.println(size);
//打印集合
System.out.println(m);
}
运行结果
false
3
{韦小宝=沐剑屏, 尹志平=小龙女, 郭靖=黄蓉}
Map的遍历方式
键找值
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MyMapDemo1 {
public static void main(String[] args) {
//Map集合的第一种方式,键找值
//1.创建Map集合的对象
Map<String, String> map = new HashMap<>();
//2.添加元素
map.put("郭靖", "黄蓉");
map.put("韦小宝", "沐剑屏");
map.put("尹志平", "小龙女");
//3.通过键找值
//3.1 获取所有的键,把这些键放到一个单列集合中
Set<String> keySet = map.keySet();
//3.2 遍历单列集合,得到每一个键
for (String key : keySet) {
//System.out.println(s);
//3.3 利用map集合中的键获取对应的值
String value = map.get(key);
System.out.println(key + "=" + value);
}
}
}
键值对
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MyMapDemo4 {
public static void main(String[] args) {
//遍历map集合第二种方式:键值对
//1.创建对象
Map<String, String> map = new HashMap<>();
//2.添加元素
map.put("标枪选手","马超");
map.put("人物挂件","明世隐");
map.put("御龙骑士","尹志平");
//通过entrySet方法获取每个键值对对象,并返回一个Set集合
Set<Map.Entry<String, String>> entries = map.entrySet();
//通过增强for对Set集合进行遍历
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey() + "=" + entry.getValue());
//System.out.println(entry);
}
}
}
Lambda表达式
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public class MyMapDemo7 {
public static void main(String[] args) {
//Map集合的第三种遍历方式:Lambdda表达式
//创建Map集合对象
Map<String, String> map = new HashMap<>();
//添加元素
map.put("鲁迅", "这句话是我说的");
map.put("曹操", "不可能绝对不可能");
map.put("刘备", "接着奏乐接着舞");
map.put("柯镇恶", "看我眼色行事");
//3.利用Lambda表达式进行遍历
//底层:
//forEach其实就是利用第二种方式进行遍历,一次得到每一个键和值,再调用accept方法
map.forEach((key,value) -> System.out.println(key + "=" + value));
System.out.println("=====================");
map.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String key, String value) {
System.out.println(key+"="+value);
}
});
}
}
Map接口的架构体系
(一)、HashMap
HashMap的特点
(1)、HashMap是Map里面的一个实现类。
(2)、没有额外需要学习的特有方法,直接使用Map里面的方法就可以了。
(3)、特点都是由键决定的:无序、不重复、无索引
(4)、HashMap跟HashSet底层原理是一摸一样的,都是哈希表结构
HashMap底层原理
首先创建长度为16,默认加载因子为0.75,根据键计算哈希值,跟值无关
HashMap底层是哈希表结构
依赖hashCode方法和equals方法保证键的唯一
如果键存储的是自定义对象,需要重写hashCode方法和equals方法
如果值存储自定义对象,不需要重写hashCode和equals方法
(二)、LinkedHashMap
LinkedHashMap
由键决定:有序、不重复、无索引
这里的有序指的是保证存储和取出的元素顺序是一致
原理:底层数据结构是依然哈希表,只是每个键值对元素又额外多了一个双链表1的机制记录存储的顺序。
(三)、TreeMap
TreeMap跟TreeSet底层原理一样,都是红黑树结构的。
由键决定特性:不重复、无索引、可排序
可排序:对键进行排序。
注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则
代码书写两种排序规则
实现Comparable接口,指定比较规则。
创建集合时传递Comparator比较器对象,指定比较规则。
可变参数
可变参数:
其本质为一个数组,方法参数的个数是可以发生改变的,在形参中接收多个数据。格式:属性类型...参数名
注意:
1、在方法的形参中最多只能写一个可变参数
2、在方法的形参中,如果出现了可变参数以外,还有其他的形参,那么可变参数要写在最后
Collections
java.util.Collections:是集合工具类
作用:Collections不是集合,而是集合的工具类。
Collections常用的API
方法名称 | 说明 |
---|---|
public static <T> boolean addAll(Collection<T> c,T... elements) | 批量添加元素 |
public static void shuffle(List<?> list) | 打乱List集合元素的顺序 |
不可变集合
不可变集合:不可以被修改的集合
运用场景:
不想让别人修改集合中的内容。
创建不可变集合的书写格式:
方法名称 | 说明 |
---|---|
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集合对象。注意:元素不能重复,键值对不能超过10个。如果超过10个使用ofEntries方法,如果JDK版本大于10,用copyOf()方法 |
注意:这个集合不能添加,不能删除,不能修改。
Stream流
Stream流的作用:结合了Lambda表达式,简化集合、数组的操作
Stream流的使用步骤:
先得到一条Stream流(流水线),并把数据放上去,利用Stream流中的API进行各种操作
中间方法:方法调用完毕之后,还可以调用其他方法
终结方法:最后一步,调用完毕之后,不能调用其他方法
(1)、先得到一条Stream流(流水线),并把数据放上去
获取方式 | 方法名 | 说明 |
---|---|---|
单列集合 | default Stream<E> stream() | Collection中大的默认的方法stream |
双列集合 | 无 | 无法直接使用stream流 |
数组 | public static <T> Stream<T> stream(T[] array) | Arrays工具类中的静态方法stream |
一堆零散数据 | public static<T>Stream<T> of(T...values) | Stream接口中的静态方法of |
Stream流的中间方法
方法名称 | 说明 |
---|---|
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流中的数据,不会影响原来集合或者数组中的数据
import java.util.ArrayList;
import java.util.Collections;
public class StreamDemo2 {
public static void main(String[] args) {
/*
* | Stream<T> filter(Predicate<? super T> predicate) | 过滤 |
* | ------------------------------------------------ | -------------- |
* | Stream<T> limit(long maxSize) | 获取前几个元素 |
* | Stream<T>skip(long n) | 跳过前几个元素 |
* */
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌","周芷若","张敏","赵明","张三丰","张翠山","张良");
list.stream()
.filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3)
.forEach(s -> System.out.println(s));
System.out.println("-------------------------------------------------------------------------------");
list.stream().limit(3).forEach(s -> System.out.println(s));
list.stream().skip(4).forEach(s -> System.out.println(s));
System.out.println("------------------------------------------------------------------");
list.stream().skip(1).limit(3).forEach(s -> System.out.println(s));
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Stream;
public class StreamDemo3 {
public static void main(String[] args) {
/*
* | tream<T>distinct() | 元素去重,依赖(hashCode和equals方法) |
* | ---------------------------------------------- | -------------------------------------- |
* | static <T> Stream<T> concat(Stream a,Stream b) | 合并a和b两个流为一个流 |*/
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌","周芷若","张敏","赵明","张三丰","张翠山","张良");
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2,"张三丰","张翠山","张良","王麻子");
Stream.concat(list1.stream(),list2.stream())
.distinct()//去重
.forEach(s -> System.out.println(s));
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;
public class StreamDemo4 {
public static void main(String[] args) {
/*
* Stream<R>map(Function<T,R> mapper)转换流中的数据类型
* */
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌-15","周芷若-14","张敏-54","赵明-34","张三丰-20","张翠山-23","张良-48");
list.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
String[] split = s.split("-");
String ageString = split[1];
int age = Integer.parseInt(ageString);
return age;
}
}).forEach(s-> System.out.println(s));
list.stream()
.map(s->Integer.parseInt(s.split("-")[1]))
.forEach(s-> System.out.println(s));
}
}
Stream流的终结方法
名称 | 说明 |
---|---|
void forEach(Consumer action) | 遍历 |
long count | 统计 |
toArray() | 收集流中的数据,放到数组中 |
collect(Collector collector) | 收集流中的数据,放到集合中 |
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.IntFunction;
public class StreamDemo5 {
public static void main(String[] args) {
/*
* | void forEach(Consumer action) | 遍历 |
* | ----------------------------- | -------------------------- |
* | long count | 统计 |
* | toArray() | 收集流中的数据,放到数组中 |
* */
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌","周芷若","张敏","赵明","张三丰","张翠山","张良");
list.stream().forEach(s-> System.out.println(s));
//long count()
long count = list.stream().count();
System.out.println(count);
//toArray() 收集流中的数据,放到数组中
Object[] arr1 = list.stream().toArray();
System.out.println(Arrays.toString(arr1));
//IntFunction的泛型:具体类型的数组
//apply的形参:流中数据的个数,要跟数组的长度保持一致
//apply的返回值:具体类型的数组
//方法体:就是创建数组
//toArray方法的参数的作用:负责创建一个指定类型的数组
//toArray方法的底层:会依次得到流里面的每一个数据,并把数据放到数组当中
//toArray方法的返回值,是一个装着流里面所有的数据的数组
String[] arr = list.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
System.out.println(Arrays.toString(arr));
String[] arr2 = list.stream().toArray(value -> new String[value]);
System.out.println(Arrays.toString(arr2));
}
}