双列集合
特点
- 双列集合一次要存一对数据,分别为键和值
- 键不能重复,值可以重复
- 键和值是一 一对应的,每一个键只能找到自己对应的值
- 键+值这个整体 我们称之为“键对值”或者“键对值对象”,在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()
//集合的长度,也就是集合中键值对的个数
put细节
添加数据时,如果键不在,那么直接把键值对对象添加到map集合当中
添加数据的时候,如果键存在,那么会把原有的键值对象覆盖,会把覆盖的值返回
Map的遍历方式
1.键找值
//创建map集合对象
Map<String, String> m = new HashMap<>();
//添加元素
m.put("奥特之父","奥特之母");
m.put("尹志平","小龙女");
//获取所有的键,把这些键放到同一个集合中
Set<String> keys = m.keySet();
//遍历单列集合,得到每一个键
for (String key : keys){
System.out.println(key);
//利用键去获取值
String value = m.get(key);
System.out.println(key + "=" + value);
键值对
//创建map集合对象
Map<String, String> m = new HashMap<>();
//添加元素
m.put("奥特之父","奥特之母");
m.put("尹志平","小龙女");
//通过一个方法获取所有键值对象,返回一个Set集合
Set<Map.Entry<String, String>>entries = m.entrySet();
//遍历entries这个集合,去得到每一个键对值对象
for (Map.Entry<String, String> entry : entries) {
//利用entry调用get方法获取键和值
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
}
Lambda表达式
//创建map集合对象
Map<String, String> m = new HashMap<>();
//添加元素
m.put("奥特之父","奥特之母");
m.put("尹志平","小龙女");
//利用Lambda表达式进行遍历
m.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String key, String value) {
System.out.println(key + "=" + value);
}
});
________________________________________________
//创建map集合对象
Map<String, String> m = new HashMap<>();
//添加元素
m.put("奥特之父","奥特之母");
m.put("尹志平","小龙女");
//利用Lambda表达式进行遍历
m.forEach(( key, value) ->System.out.println(key + "=" + value));
}
HashMap
特点
- HashMap是Map里面的一个实现类
- 没有额外需要学习的特有方法,直接使用Map里面的方法就可以
- 特点都是由键决定的: 无序,不重复,无索引
练习1
需求:
创建一个HashMap集合,键是学生对象(Student),值是籍贯(String).
存储三个键值对元素,并遍历
要求:同姓名,同年龄认为是同一个学生
package com.itheima.a01.mymap;
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);
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
public static void main(String[] args) {
//创建HashMap对象
HashMap<Student,String> hm = new HashMap<>();
//创建3个学生对象
Student s1 = new Student("zhangsan",34);
Student s2 = new Student("lisi",34);
Student s3 = new Student("wangwu",34);
//3.添加元素
hm.put(s1,"山东");
hm.put(s2,"浙江");
hm.put(s3,"江苏");
//遍历
Set<Student> keys = hm.keySet();
for (Student key : keys){
String value= hm.get(key);
System.out.println(key+ "="+ value);
}
System.out.println("--------------------------------------------------");
Set<Map.Entry<Student, String>> entries = hm.entrySet();
for (Map.Entry<Student, String> entry : entries) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
System.out.println("--------------------------------------------------");
hm.forEach(( student, s) -> System.out.println(student + "=" + s)
);
}
练习二
需求:
某个班80名学生,现在需要组成秋游活动
班长提供了四个景点(A,B,C,D)
每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多
import java.util.*;
public class A03demo {
public static void main(String[] args) {
//先让同学们进行投票
//定义一个数组存储四个景点
String[] arr = {"A","B","C","D"};
//利用随机数模拟80个同学投票,并把投票结果存储
ArrayList<String> list = new ArrayList<>();
Random r = new Random();
for (int i = 0; i < 80 ; i++){
int index = r.nextInt(arr.length);
list.add(arr[index]);
}
//定义map集合,利用集合进行统计
HashMap<String,Integer> hm = new HashMap<>();
for (String name : list){
//判断当前景点在map中是否存在
if(hm.containsKey(name)){
//存在
//先获取当前景点已经出现的次数
int count = hm.get(name);
//表示当前景点又被投了一次
count++;
//把新的集合次数再次添加到集合当中
hm.put(name,count);
}else {
//不存在
hm.put(name,1);
}
}
System.out.println(hm);
//求最大值
int max = 0;
Set<Map.Entry<String, Integer>> entries = hm.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
int count = entry.getValue();
if (count>max){
max = count;
}
}
System.out.println(max);
//判断最大值是哪一个
for (Map.Entry<String, Integer> entry : entries) {
int count = entry.getValue();
if (count==max){
System.out.println(entry.getKey());
}
}
}
}
LinkedHashMap
由键决定:有序,不重复,无索引
这里的有序指的是保证存储和取出元素顺序一致
原理:底层数据结构依然是哈希表,只是每个键对元素有额外多了一个双链表的机制记录存储顺序
TreeMap
TreeMap跟TreeSet底层原理一样,都是红黑树结构的
由键决定特性:不重复、无索引、可排序
可排序:对键进行排序
注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则
代码书写两种排序规则
实现Comparable接口,指定比较规则
创建集合时传递Comparator比较器对象,指定比较规则
TreeMap基本应用
需求1:
键:整数表示id
值:字符串表示商品名称
要求:按照id的升序排列,按照id降序排列
//创建集合对象
TreeMap<Integer,String> tm = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
//添加元素
tm.put(1,"月里约");
tm.put(2,"纯牛马");
tm.put(3,"省巢");
//打印集合
System.out.println(tm);
需求2:
键:学生对象
值:籍贯
要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为同一个人
package a02treemap;
public class Student implements Comparable<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;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
@Override
public int compareTo(Student o) {
int i =this.getAge() - o.getAge();
i = i == 0 ? this.getName().compareTo(o.getName()) : i;
return i;
}
}
//创建集合
TreeMap<Student,String> tm = new TreeMap<>();
//创建3个学生对象
Student s1 = new Student("zhangsan",23);
Student s2 = new Student("lisi",23);
Student s3 = new Student("wangwu",23);
//添加元素
tm.put(s1,"江苏");
tm.put(s2,"山东");
tm.put(s3,"浙江");
//打印
System.out.println(tm);
可变参数
public static void main(String[] args){
getSum(...args:1,2,3,4,5,6,7,8,9,10);
}
public static int getSum(int...args){
}
底层:
可变参数底层就是一个数组
只不过不需要我们自己创建,java会帮我们创建好
可变参数的小细节:
1、在方法的形参中最多只能写一个可变参数
可变参数,理解为一个大胖子,有多少吃多少
2、在方法的形参当中,如果出现了可变参数意外,还有其他的形参,那么可变参数要写在最后
Collection
作用;collection不是集合,而是集合工具类
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 binarySearch (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)
//交换集合中指定位置的元素
斗地主(欠着)
不可变集合
创建不可变集合:不可以被修改的集合
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集合对象
创建map集合的细节:
1.键不能重复
2.Map里面的of方法,参数是有上限的,最多只能传20个参数,10个键值对
Stream流
体验Stream流的作用
需求:按照下面的要求完成集合的创建和遍历
创建一个集合,存储多个字符串元素
1、把所有以“张”开头的元素存储到新集合中
2、把“张”开头的,长度为三的元素再存储到新的集合中
3、遍历打印最终结果
ArrayList<String> list1 = new ArrayList<>();
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));
Stream流的思想
结合了Lambda表达式,简化集合、数组的操作
Stream流的使用步骤
过滤——转换——中间方法——方法调用完毕之后,还可以调用其他方法
统计——打印——终结方法——最后一步,调用完毕之后,不能调用其他方法
1、先得到一条Stream流(流水线),并把数据放上去
2、使用中间方法对流水线按上的数据进行操作
3、使用中介方法对流水线上的数据进行操作
单列集合
default Stream <E> stream()
//Collection中的默认方法
双列集合——没有方法名——无法直接使用Stream流
数组
public static<T> Stream<T>stream(T[] array)
//Arrays工具类中的静态方法
Stream接口中静态方法of的细节
方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
但是数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当作一个元素,放到Stream中
Stream流的中间方法
Stream<T> filter(Predicate<? super T> predicate)
//过滤
Stream<T> limit(long maxSize)
//获取前几个元素
Steram<T> skip(long n)
//跳过前几个元素
Steram<T> distinct()
//元素去重,依赖hashCode和equals方法
static <T> Steram<T>concat(Stream a,Stream b)
//合并a和b两个流为一个流
Steram<R> map(Function<T,R> mapper)
//转换流中的数据类型