Java的集合有关知识:
Java集合框架提供了一套性能优良,使用方便的接口和类,主要包括两种类型的容器:集合(Collection)
和 图(Map)
。集合存储一个元素集合 ,图存储键/值对映射 。Collection 接口有三种子类型:List 、Set 和Queue ,而Map 接口下包含了如HashMap 和TreeMap等具体实现类。
集合和数组的区别
集合与数组都可以存储引用数据类型的对象,但集合提供了更多的数据操作方法,并且可以动态扩展容量
。数组在初始化后长度固定,而集合长度可变,更加灵活。
Collection接口的方法(单列集合)
Collection接口是 List *、Set 和Queue接口的父接口,定义了一些通用的方法*,如
add(e), 添加一个元素
remove(e),删除一个元素
clear(),清空所有元素
contains(object obj),判断是否包含当前元素
isEmpty(),判断是否为空
size(),获取该集合的元素个数
toArray(),把集合的元素转存储到数组中
用于操作集合数据。
集合的遍历:
1、iterator遍历迭代器
2、增强for循环
3、通过lambda表达式进行遍历
java
public static void main(String[] args) {
Collection<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
//TODO:进行遍历
// 通过遍历迭代器iterator
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
System.out.println(s);
}
//TODO: 通过增强for进行遍历
for (String s : list) {
System.out.println(s);
}
//TODO: 通过lambda表达式进行遍历
// lambda的原型(函数式接口Consumer泛型的类型和集合的泛型类型一样)
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
list.forEach(s -> System.out.println(s));
}
在进行集合遍历的修改并发异常问题:
1、通过i--的方法解决
2、通过迭代器的形式进行解决
java
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("人字拖");
list.add("老九门");
list.add("枸杞子");
list.add("Java");
list.add("好枸杞");
list.add("黑枸杞");
list.add("枸和杞子");
System.out.println(list);
// TODO:并发修改异常
for (int i = 0; i < list.size(); i++) {
if (list.get(i).contains("枸杞")) {
list.remove(i);
i--;
}
}
System.out.println(list);
// TODO:通过迭代器的形式进行遍历修改异常处理
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
if (s.contains("枸杞")) {
iterator.remove();
}
}
System.out.println(list);
}
TreeSet不能对于自定义对象进行排序:
解决方式:
1、需要实现Comparable接口重写其对应的compareTo方法
java
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
public class Student implements Comparable<Student> {
private String name;
private int age;
private int score;
private String sex;
@Override
public int compareTo(Student o) {
return o.getScore()-this.getScore();//降序
//return this.getScore()-o.getScore();//升序
}
}
2、在创建TreeSet对象的时候
java
new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getScore()-o2.getScore();//升序
//return o2.getScore()-o1.getScore();//降序
}
});
List和Set的区别
-
List:
有序
集合,可以包含重复元素(可重复
),可以通过索引访问元素(有索引
)有序是指对应的存入顺序是有序的 -
ArrayList:底层基于数组的思想---》查询数据快(可以扩容)
第一次在添加数据的时候所创建的默认长度为10
-
LinkedList:底层是通过链表的形式----》增删数据快
-
Set :
无序
集合,不允许有重复元素(不重复
),主要实现类有HashSet 和LinkedHashSet 和TreeSet。 -
HashSet:
无序
,不重复,无索引第一次在添加数据的时候所创建的默认长度为16
-
LinkedHashSet:
有序
,不重复,无索引(有序是存入顺序有序) -
TreeSet:
按照值的大小默认升序排序
,不重复,无索引
HashSet对于对象的泛型进行去重
方法:通过重写对象的equals方法和hashCode方法(通过右键直接生成)
java
//TODO:重写equals方法,重写hashCode方法
@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 && score == student.score && Objects.equals(name, student.name) && Objects.equals(sex, student.sex);
}
@Override
public int hashCode() {
return Objects.hash(name, age, score, sex);
}
Map接口(双列集合)键值对集合
Map系列的集合的特点都是由键决定的
Map
提供键到值的映射,每个键最多只能映射到一个值
键名不能重复,值可以重复
主要实现类包括HashMap 和TreeMap----》(不重复是针对于键是否重复,对应的值是可以重复的)
键值对的遍历:
1、获取所有的键返回为一个Set集合,遍历Set,通过键获取值
2、遍历Map集合的另外一种方式:Map调用entrySet方法转为一个Set对象进行遍历
3、通过foreach进行遍历
java
public static void main(String[] args) {
// TODO: 对于Map键值对的遍历
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("张三", 18);
hashMap.put("李四",32);
hashMap.put("王五", 20);
hashMap.put("赵六", 21);
// 1. 获取所有的键返回为一个Set集合
Set<String> keys = hashMap.keySet();
// 2、遍历Set集合
for (String key : keys) {
// 3、通过键获取值
Integer value = hashMap.get(key);
System.out.println(key + "=" + value);
}
// TODO: 遍历Map集合的另外一种方式:Map调用entrySet方法
Set<Map.Entry<String, Integer>> entries = hashMap.entrySet();
for (Map.Entry<String, Integer> entry : entries){
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + "=" + value);
}
}
java
// TODO: 遍历Map集合的另外一种方式:通过foreach进行遍历
hashMap.forEach(new BiConsumer<String, Integer>() {
@Override
public void accept(String key, Integer value) {
System.out.println(key + "=" + value);
}
});
//简写
hashMap.forEach((key,value)-> System.out.println(key + "=" + value));
HashMap允许存储一个null键和多个null值-》(无序,不重复,无索引)
TreeMap则按照比较器(Comparator)或自然排序(Comparable)对键进行排序。-》(按照默认大小排序,不重复,无索引)
线程安全和非线程安全的探究
集合类按线程安全性可分为线程安全和非线程安全两类。例如,Vector和Hashtable是线程安全的,而ArrayList和HashMap是非线程安全的
。
集合的数据结构
- ArrayXxx:底层数据结构是数组,查询快,增删慢。
- LinkedXxx:底层数据结构是链表,查询慢,增删快。
- HashXxx :底层数据结构是哈希表,依赖*hashCode()和equals()*方法。
- TreeXxx:底层数据结构是二叉树,元素有序。
集合的选择
选择使用哪种集合类,取决于具体的应用场景。例如,当需要频繁读取数据时,应选择ArrayList ;当需要频繁插入或删除数据时,应选择LinkedList ;当需要元素唯一且无序时,应选择HashSet ;当需要排序时,应选择TreeSet。
Stream流
通过集合对象的stream()
方法获取集合对应的Stream流
java
public static void main(String[] args) {
// TODO:集合怎么获取对应的Stream流
// Collection取对应的Stream流
Collection<String> list = new ArrayList<>();
list.stream();
// Map取对应的Stream流
//通过键或值获取对应的Stream流
Map<String, Integer> hashMap = new HashMap<>();
// 获取对应的键的Stream流
hashMap.keySet().stream();
// 获取对应的值的Stream流
hashMap.values().stream();
//TODO:数组怎么获得对应的Stream流
String[] arr = new String[]{"张三","李四","王五"};
Stream<String> stream = Stream.of(arr);
//通过Arrays类获取stream流
Stream<String> stream1 = Arrays.stream(arr);
}
常用方法:
1.forEach(终结方法)
用于遍历的方法,参数传入一个函数式接口:Consumer
java
public static void main(String[] args) {
Stream<String> stream = Stream.of("张无忌", "张三丰", "周芷若");
stream.forEach(name‐> System.out.println(name));
}
2.过滤:filter
可以用于过滤
可以通过 filter 方法将一个流转换成另一个子集流。
java
public static void main(String[] args) {
//创建一个流
Stream<String> stream = Stream.of("张三丰", "刘德华", "张国荣", "彭于晏", "纳什", "吴彦祖", "吴绮蓉");
//对流中元素过滤,只要姓张的人
Stream<String> stream2 = stream.filter(name -> {
return name.startsWith("张");
});
//遍历过滤后的流
stream2.forEach(name -> System.out.println(name));
}
3、统计个数:count(终结方法)
正如旧集合 Collection 当中的 size 方法一样,流提供 count 方法来数一数其中的元素个数
4、查找最大最小值(终结方法)
max(comparator c)
min(comparator c)
java
/**
* 查找最大最小值
*/
@Test
public void test5(){
List<Person> list = new ArrayList<>();
list.add(new Person("马化腾",25,3000));
list.add(new Person("李彦宏",27,2545));
list.add(new Person("雷军",35,4515));
list.add(new Person("马云",55,9877));
// 查找年龄最大的人
Optional<Person> max = list.stream().max((e1, e2) -> e1.getAge() - e2.getAge());
// 返回马云,55岁年龄最大
System.out.println(max.get());
System.out.println("--------");
5、收集(终结方法)
collect(Collector c):将流转化为其他形式,接收一个Collector接口的实现
java
/**
* 收集的练习
*/
@Test
public void test7(){
List<Person> list = new ArrayList<>();
list.add(new Person("马化腾",25,3000));
list.add(new Person("李彦宏",27,2545));
list.add(new Person("雷军",35,4515));
list.add(new Person("马云",55,9877));
// 把年龄大于30岁的人,转成一个list集合
List<Person> collect = list.stream().filter(person -> person.getAge() > 30).collect(Collectors.toList());
// 遍历输出(输出雷军和马云)
for (Person person : collect) {
System.out.println(person);
}
System.out.println("----------");
List<Person> list2 = new ArrayList<>();
list2.add(new Person("马化腾",25,3000));
list2.add(new Person("李彦宏",27,2545));
list2.add(new Person("雷军",35,4515));
list2.add(new Person("马云",55,9877));
// 把姓马的人,转成Set集合
Set<Person> set = list2.stream().filter(person -> person.getName().startsWith("马")).collect(Collectors.toSet());
// 输出马云和马化腾
set.forEach(System.out::println);
}