Set容器
Set容器中的方法与Collection方法基本一致
Set集合去重复只需要重写集合存储类的equals/hashCode方法
HashSet集合
底层基于哈希表实现
哈希值:一个int类型的随机值,java中的每个对象都有一个哈希值(通过object类的hashCode方法获取值)
对象哈希值的特点
- 同一个对象多次调用hashCode方法返回的哈希值是相同的。
- 不同的对象,它们的哈希值大概率不相等,但也有可能会相等(哈希碰撞)。
哈希碰撞:int类型范围是-21亿~21亿,当超出这个范围哈希值就会发生重复即为碰撞。
哈希表
- jdk8之前,哈希表=数组+链表实现,jdk8之后,哈希=数组+链表+红黑树
- 哈希表是一种增删改查数据,性能都较好的数据结构
哈希表存储过程
-
创建一个默认长度16的数组,默认加载因子为0.75,数组名table
-
使用元素的哈希值对数组的长度做运算计算出应存入的位置
-
判断当前位置是否为null,如果是null直接存入
-
如果不为null,表示有元素,则调用equals方法比较相等,则不存;不相等,则存入数组
-
JDK 8之前,新元素存入数组,占老元素位置,老元素挂下面
-
JDK 8开始之后,新元素直接挂在老元素下面
-
哈希表的扩容变化
- 数组长度*加载因子=扩容长度;当数组长度达到扩容长度则会进行两倍扩容
- 当链表长度超过8,且数组长度>=64时,自动将链表转成红黑树(JDK8开始之后)
LinkedHashSet集合
底层基于哈希表(数组+链表+红黑树)实现的。
每个元素都额外的多了一个双链表的机制记录它前后元素的位置。
TreeSet集合
基于红黑树实现(通过指定的比较器Comparator来判断元素是否重复)
// 子类特定方法
public boolean addAll(Collection<? extends E> c); // 添加集合中的所有元素
public E first() // 返回第一个元素
public E last() // 返回最后一个元素
默认从小到大进行元素排序,若存储自定义对象则需要给对象制定比较规则。
- 方案1:让对象的类实现Comparable接口,重写
compareTo方法,声明大小规则。 - 方案2:TreeSet集合自带抽象比较器对象,通过有参构造器实现容器中的比较器,来制定比较规则。
// 方案1
public class Student implements Comparable<Student> {
private String name;
private Integer age;
private double score;
private String address;
// 实现比较器
@Override
public int compareTo(Student o) {
// 从小到大
return Double.compare(this.getScore(), o.getScore());
}
}
// 方案2 匿名函数,实现TreeSet内部的抽象比较函数
Set<User> users = new TreeSet<>(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return Double.compare(o1.getScore(), o2.getScore());
/*if(o1.getScore() > o2.getScore()){
return 1;
}else if (o1.getScore() < o2.getScore()){
return -1;
}
return 0;*/
}
});
Map集合的体系
Set集合中的HashSet/LinkedHashSet/TreeSet等集合底层都是Map集合中对应的容器实现。
Set集合只是使用了Map集合中的Key存储数据。
TreeMap集合(通过指定的比较器Comparator来判断元素是否重复)
常用方法
| 方法名称 | 说明 |
|---|---|
| public V put(K key,V value) | 添加元素 |
| public int size() | 获取集合的大小 |
| public void clear() | 清空集合 |
| public boolean isEmpty() | 判断集合是否为空,为空返回true , 反之 |
| public V get(Object key) | 根据键获取对应值 |
| public V remove(Object key) | 根据键删除整个元素 |
| public boolean containsKey(Object key) | 判断是否包含某个键 |
| public boolean containsValue(Object value) | 判断是否包含某个值 |
| public Set keySet() | 获取全部键的集合 |
| public Collection values() | 获取Map集合的全部值 |
遍历方式
Map<Integer, String> map = new HashMap<>();
map.put(1, "张三");
map.put(2, "李四");
map.put(3, "王五");
map.put(4, "赵六");
// 方法一
for (Integer i : map.keySet()) {
System.out.print(map.get(i)+" ");
}
System.out.println();
// 方法二
for (Map.Entry<Integer, String> item : map.entrySet()) {
System.out.print(item.getKey()+" ");
System.out.print(item.getValue()+"\t");
}
System.out.println();
// 方法三 内部通过的方法二中的entrySet()实现
map.forEach((k,v)->{
System.out.print(k+" "+v+"\t");
});
Stream流(JDK8之后)
获取Stream流
List<Student> list = new ArrayList<>();
Stream<Student> stream = list.stream(); // Collection集合含有stream方法
String[] arr = {"张三", "李四", "王五", "赵六"};
Stream<String> s1 = Arrays.stream(arr);
Stream<String> s2 = Stream.of(arr); // Stream.of 为静态方法,of参数为数组数据。
处理Stream流(常用方法)
| Stream提供的常用中间方法 | 说明 |
|---|---|
| Stream filter(Predicate<? super T> predicate) | 用于对流中的数据进行过滤。 |
| Stream sorted() | 对元素进行升序排序 |
| Stream sorted(Comparator<? super T> comparator) | 按照指定规则排序 |
| Stream limit(long maxSize) | 获取前几个元素 |
| Stream skip(long n) | 跳过前几个元素 |
| Stream distinct() | 去除流中重复的元素。 |
| Stream map(Function<? super T,? extends R> mapper) | 对元素进行加工,并返回对应的新流 |
| static Stream concat(Stream a, Stream b) | 合并a和b两个流为一个流 |
List<Student> list = new ArrayList<>();
list.add(new Student("张三", 18, 100, "北京"));
list.add(new Student("李四", 19, 90, "上海"));
list.add(new Student("李四", 42, 90, "上海"));
list.add(new Student("王五", 20, 80, "广州"));
list.add(new Student("赵六", 45, 70, "深圳"));
list.add(new Student("赵六", 45, 70, "深圳"));
list.stream().filter(student -> student.getAge() > 18).forEach(System.out::println);
// 调用Student中的比较方法,类需要实现Comparable接口中的compareTo方法
list.stream().sorted().forEach(System.out::println);
list.stream().sorted(Comparator.comparingInt(Student::getAge)).forEach(System.out::println);
list.stream().limit(2).forEach(System.out::println);
list.stream().skip(2).forEach(System.out::println);
list.stream().distinct().forEach(System.out::println);
list.stream().map(Student::getName).forEach(System.out::println);
Stream<String> s1 = list.stream().map(Student::getName);
Stream<Student> s2 = list.stream().filter(student -> student.getScore() > 60);
Stream<Object> o = Stream.concat(s1,s2);
o.forEach(System.out::println);
收集Stream流
| Stream提供的常用终结方法 | 说明 |
|---|---|
| void forEach(Consumer action) | 对此流运算后的元素执行遍历 |
| long count() | 统计此流运算后的元素个数 |
| Optional max(Comparator<? super T> comparator) | 获取此流运算后的最大值元素 |
| Optional min(Comparator<? super T> comparator) | 获取此流运算后的最小值元素 |
| R collect(Collector collector) | 把流处理后的结果收集到一个指定的集合中去 |
| Object[] toArray() | 把流处理后的结果收集到一个数组中去 |
| Collectors工具类提供了具体的收集方式 | 说明 |
|---|---|
| public static Collector toList() | 把元素收集到List集合中 |
| public static Collector toSet() | 把元素收集到Set集合中 |
| public static Collector toMap(Function keyMapper , Function valueMapper) | 把元素收集到Map集合中 |
List<Student> list = new ArrayList<>();
list.add(new Student("张三", 18, 100, "北京"));
list.add(new Student("李四", 19, 90, "上海"));
list.add(new Student("李四", 42, 50, "上海"));
list.add(new Student("王五", 20, 80, "广州"));
list.add(new Student("赵六", 45, 70, "深圳"));
list.stream().map((s) -> s.getScore()).forEach(x -> System.out.print(x+" "));
long l = list.stream().map((s) -> s.getScore()).count();
System.out.println(l);
Optional<Student> min = list.stream().min((s1, s2) -> s1.getScore() - s2.getScore());
System.out.println(min.get());
Optional<Student> max = list.stream().max((o1, o2) -> o1.getAge() - o2.getAge());
System.out.println(max.get());
list.stream().filter(s -> s.getName().startsWith("李")).collect(Collectors.toList());
list.stream().filter(s -> s.getName().startsWith("李")).collect(Collectors.toSet());
Object[] ss = list.stream().filter(s -> s.getName().startsWith("李")).toArray();
System.out.println(Arrays.toString(ss));
Map<Integer,String> map = list.stream().filter(s -> s.getName().startsWith("李")).collect(Collectors.toMap(Student::getAge,Student::getName));
map.forEach((k,v) -> System.out.println(k+" "+v));
可变参数
格式:数据类型...参数名称
可变参数的特点和好处
- 特点
- 可以不传数据给它
- 可以传一个或者同时传多个数据给它
- 也可以传一个数组给它
- 好处:常常用来灵活的接收数据
可变参数的注意事项
- 可变参数在方法内部就是一个数组
- 一个形参列表中可变参数只能有一个
- 可变参数必须放在形参列表的最后面
public void sum(int age,int...num){
System.out.println(age);
System.out.println(Arrays.toString(num));
}
Collections工具类
| 方法名称 | 说明 |
|---|---|
| public static boolean addAll(Collection<? super T> c, T... elements) | 给集合批量添加元素 |
| public static void shuffle(List<?> list) | 打乱List集合中的元素顺序 |
| public static void sort(List list) | 对List集合中的元素进行升序排序 |
| public static void sort(List list,Comparator<? super T> c) | 对List集合中元素,按照比较器对象指定的规则进行排序 |
Collections.addAll(list,new Student("1",2,3,"4"));
Collections.shuffle(list);
Collections.sort(list); // 默认升序
Collections.sort(list, (s1,s2) -> s1.getAge() - s2.getAge()); // 自定义排序