目录
1.异常
1.1 认识异常
package com.itheima.d1_exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo1 {
public static void main(String[] args) throws ParseException {
// 目标:认识异常。
System.out.println("===开始===");
int[] arr = {11, 22, 33};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
// System.out.println(arr[3]); // ArrayIndexOutOfBoundsException 数组索引越界异常
String name = null;
// System.out.println(name.length()); // NullPointerException 空指针异常
// System.out.println(10 / 0); // ArithmeticException 数学操作异常
Object o = "张麻子";
//编译阶段不会报错,运行报错类型转换异常
// Integer i = (Integer) o; // ClassCastException 类型转换异常
String s = "23a";
int it = Integer.valueOf(s); // NumberFormatException 数字转换化异常
System.out.println(it);
parseDate("2024-03-19 13:20:31");
System.out.println("===结束===");
}
//抛出异常
public static void parseDate(String s) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(s); // 编译时异常,写代码时就标红报错!
System.out.println(d);
}
}
1.2 自定义异常
我们可以用try{}catch{}来捕获异常。
package com.itheima.d1_exception;
public class ExceptionDemo2 {
public static void main(String[] args) {
//目标:搞清楚异常的作用。
System.out.println("开始...");
try {
System.out.println(divide(10, 2));
System.out.println("成功了!");
} catch (Exception e) {
System.out.println("失败了!");
//捕获异常,并打印出异常信息
e.printStackTrace();//打出这个异常信息
}
System.out.println("结束...");
}
public static int divide(int a, int b){
if (b == 0){
System.out.println("参数有问题~~~");
//return -1;//返回-1有可能除的结果就是-1与真正结果重复
//抛出一个异常作为返回值,通知上层,这里出现了bug
throw new RuntimeException("/ by 0! ");
}
int c = a / b;
return c;
}
}
自定义运行时异常:
package com.itheima.d1_exception;
public class ExceptionDemo3 {
public static void main(String[] args) {
// 目标:自定义异常。
System.out.println("开始....");
try {
save(50);
System.out.println("执行成功了");
} catch (Exception e) {
e.printStackTrace();//打印异常信息
System.out.println("执行失败了");
}
System.out.println("结束....");
}
public static void save(int age){
if (age <= 0 || age > 150){
//这个年龄非法!创建异常对象并立即抛出去
//不能用输出语句,如果用输出语句项目上线并没有控制台,看不到异常信息
throw new ItheimaAgeIllegalRuntimeException("/age is xiagao!");
}
System.out.println("年龄保存成功了,年龄是:" + age);
}
}
package com.itheima.d1_exception;
// 自定义运行时异常
/**
1、继承 RuntimeException
2、重写构造器
*/
public class ItheimaAgeIllegalRuntimeException extends RuntimeException{
public ItheimaAgeIllegalRuntimeException() {
}
public ItheimaAgeIllegalRuntimeException(String message) {
super(message);
}
}
自定义编译时异常:
package com.itheima.d1_exception;
public class ExceptionDemo4 {
public static void main(String[] args) {
// 目标:自定义异常2。
System.out.println("开始。。。。");
try {
save(250);
System.out.println("执行成功了");
} catch (Exception e) {
e.printStackTrace(); // 打印异常对象信息
System.out.println("执行失败了");
}
System.out.println("结束。。。。");
}
public static void save(int age) throws ItheimaAgeIllegalException {
// throw 方法内部使用的,创建异常并从此点抛出去。
// throws 方法上,抛出方法内部的异常给调用者。
if(age <= 0 || age > 150){
// 这个年龄非法!创建异常对象并立即抛出去
throw new ItheimaAgeIllegalException("/age is xiagao!");
}
System.out.println("年龄保存成功了,年龄是:" + age);
}
}
package com.itheima.d1_exception;
// 自定义编译时异常
/**
1、继承 Exception
2、重写构造器
*/
public class ItheimaAgeIllegalException extends Exception{
public ItheimaAgeIllegalException() {
}
public ItheimaAgeIllegalException(String message) {
super(message);
}
}
我们应该尽量定义运行时异常,编译时异常的耦合性问题如:底层方法的异常(如数据库连接异常)会逐层向上传播,迫使上层业务代码处理与业务无关的技术异常,对程序员干扰强烈。
1.3 异常的处理
底层异常往外抛,最外层集中捕获,代码能写过去即可。
package com.itheima.d1_exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo5 {
public static void main(String[] args) {
// 目标:异常的处理机制
System.out.println("===开始===");
try {
parseDate("2023-11-11 11:11:11");
System.out.println("成功了");
} catch (Exception e) {
e.printStackTrace();
System.out.println("失败了!");
}
System.out.println("===结束===");
}
public static void parseDate(String s) throws ParseException, FileNotFoundException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(s);//编译时异常,写代码时就报错!
System.out.println(d);
InputStream is = new FileInputStream("D:/meinv.png");
}
}
package com.itheima.d1_exception;
import java.util.Scanner;
public class ExceptionDemo6 {
public static void main(String[] args) {
// 目标:异常的处理方式2:捕获异常,尝试修复。
while (true) {
try {
double price = getPrice();
System.out.println("本商品定价是:" + price);
break;
} catch (Exception e) {
System.out.println("您输入的价格是瞎搞的!");
}
}
}
public static double getPrice(){
Scanner sc = new Scanner(System.in);
System.out.println("请您输入一个合法的价格:");
double price = sc.nextDouble();
return price;
}
}
2.集合体系架构
2.1 Collection集合体系
2.2 Collection的方法
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class CollectionAPTDemo1 {
public static void main(String[] args) {
// 目标:掌握Collection提供的常用方法:是全部单列集合都可以直接用的。
Collection<String> list = new ArrayList<>(); // 多态
// 1、添加数据 boolean add(E e)
list.add("java1");
list.add("java1");
list.add("赵敏");
list.add("赵敏");
list.add("小昭");
list.add("灭绝师太");
System.out.println(list); // [java1, java1, 赵敏, 赵敏, 小昭, 灭绝师太]
// 2、清空集合
//list.clear();
//System.out.println(list); // []
// 3、判断集合是否为空
System.out.println(list.isEmpty());
// 4、直接删除集合中的某个数据:默认只能删除第一个java1
System.out.println(list.remove("java1"));
System.out.println(list);
// 5、判断集合中是否包含某个数据
System.out.println(list.contains("java1")); // true
System.out.println(list.contains("Java1")); // false
// 6、获取集合的大小(元素个数)
System.out.println(list.size());
// 7、把集合转化成数组。
Object[] array = list.toArray();
System.out.println(Arrays.toString(array));
// 拓展
String[] arrays = list.toArray(String[]::new);
System.out.println(Arrays.toString(arrays));
// 8、拓展一下:把别人集合的数据加给自己
Collection<String> c1 = new ArrayList<>();
c1.add("java1");
c1.add("java2");
Collection<String> c2 = new ArrayList<>();
c2.add("java2");
c2.add("java3");
// 把c2集合的数据全部倒入给c1集合
c1.addAll(c2);
System.out.println(c1);
System.out.println(c2);
}
}
2.3 Collection的遍历方式
2.3.1 迭代器
package com.itheima.d4_collection_travesal;
import java.util.ArrayList;
import java.util.Iterator;
public class CollectionDemo1 {
public static void main(String[] args) {
// 目标:掌握Collection集合的遍历方式一:迭代器遍历。
// 1、准备一个集合
ArrayList<String> list = new ArrayList<>();
list.add("赵敏");
list.add("古力娜扎");
list.add("马尔扎哈");
System.out.println(list);
// list = [赵敏, 古力娜扎, 马尔扎哈]
// it
// 2、得到这个集合对象的迭代器对象。
Iterator<String> it = list.iterator();
//先把第一个取完,然后把指针移动到下一个
// System.out.println(it.next());
// System.out.println(it.next());
// System.out.println(it.next());
// System.out.println(it.next());
// 3、使用循环改进
while (it.hasNext()){
String ele = it.next();
System.out.println(ele);
}
}
}
2.3.2 增强for
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class CollectionDemo2 {
public static void main(String[] args) {
// 目标:掌握Collection集合的遍历方式二:增强for(foreach遍历)。
// 1、准备一个集合
Collection<String> list = new ArrayList<>();
list.add("赵敏");
list.add("古力娜扎");
list.add("马尔扎哈");
list.add("卡扎菲");
// 2、增强for循环遍历集合
for (String s : list) {
System.out.println(s);
}
// 3、注意:增强for也可以遍历数组。
int[] ages = {19,18,34,25};
for (int age : ages) {
System.out.println(age);
}
}
}
注意:
增强for循环的本质:它是Java提供的一种语法糖,在编译之后会被转化成传统的for循环或者迭代器,在遍历数组时,他会转化成普通的for循环;而遍历集合时,则会使用迭代器。
增强for循环无法修改元素值:在增强for循环里,element是集合或数组中元素的一个副本,并非元素本身。所以,修改element的值,仅仅是改变了这个临时副本,并不会对原始集合或数组里的元素造成影响。
2.3.3 lambda表达式
package com.itheima.d4_collection_travesal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
public class CollectionDemo3 {
public static void main(String[] args) {
// 目标:掌握Collection集合的遍历方式三:lambda表达式
// 1、准备一个集合
ArrayList<String> list = new ArrayList<>();
list.add("赵敏");
list.add("古力娜扎");
list.add("马尔扎哈");
list.add("卡扎菲");
//list.forEach()方法接受一个Consumer<String>函数式接口作为参数
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
list.forEach(s -> System.out.println(s));
list.forEach(System.out::println);
}
}
2.3.4 遍历对象
package com.itheima.d4_collection_travesal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
public class Test4 {
public static void main(String[] args) {
// 1、创建集合
Collection<Movie> movies = new ArrayList<>();
// 2、存入电影对象
movies.add(new Movie("《消失的她》", "文咏珊,倪妮", 9.5));
movies.add(new Movie("《八角笼中》", "王宝强", 7.5));
movies.add(new Movie("《三万里》", "李白", 8.5));
// 3、遍历集合中的每个电影对象。
for (Movie m : movies) {
System.out.println(m.getName() + " " + m.getActor() + " " + m.getScore());
}
}
}
2.3.5 集合的并发修改异常
package com.itheima.d4_collection_travesal;
import java.util.ArrayList;
import java.util.Iterator;
public class CollectionTest5 {
public static void main(String[] args) {
// 目标:三种遍历可能出现的并发修改异常问题。
ArrayList<String> list = new ArrayList<>();
list.add("Java入门");
list.add("宁夏枸杞");
list.add("黑枸杞");
list.add("人字拖");
list.add("特技枸杞");
list.add("枸杞子");
// 1、使用迭代器遍历集合并删除枸杞:
// 注意1:如果使用迭代器遍历,并用集合删除数据,会出现并发修改异常,程序出现bug。
// 注意2: 必须调用迭代器自己的删除方法,才不会出现bug
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String name = it.next();
if(name.contains("枸杞")){
//list.remove(name);//如果使用迭代器遍历,并用集合删除数据,会出现并发修改异常,程序出现bug
it.remove();//必须调用迭代器自己的删除方法,才不会出现bug
//相当于在内部做了一步i--
}
}
System.out.println(list);
// 2、使用增强for遍历集合并删除枸杞:(本质就是迭代器) 一定会出错,而且无法解决。
ArrayList<String> list2 = new ArrayList<>();
list2.add("Java入门");
list2.add("宁夏枸杞");
list2.add("黑枸杞");
list2.add("人字拖");
list2.add("特技枸杞");
list2.add("枸杞子");
// for (String name : list2) {
// if(name.contains("枸杞")){
// list2.remove(name);
// }
// }
// System.out.println(list2);
// 3、Lambda遍历集合并删除:一定会出错,而且无法解决。
ArrayList<String> list3 = new ArrayList<>();
list3.add("Java入门");
list3.add("宁夏枸杞");
list3.add("黑枸杞");
list3.add("人字拖");
list3.add("特技枸杞");
list3.add("枸杞子");
list3.forEach(name -> {
if(name.contains("枸杞")){
list3.remove(name);
}
});
// 注意:如果是Arraylist带索引的集合,我们也可以使用for循环删除每次退一步,或者从后面倒着遍历并删除!
}
}
如果要遍历的同时删除元素,我们可以使用迭代器自己的remove删除方法,才不会出现bug。
如果只是遍历元素,我们可以使用增强for循环和foreach方法
2.4 List集合
2.4.1 特点、特有方法
package com.itheima.d5_list;
import java.util.ArrayList;
import java.util.List;
public class ListDemo1 {
public static void main(String[] args) {
// 目标:掌握List的特有方法。
// 1、创建一个List集合对象:(一行经典代码)
List<String> list = new ArrayList<>();//多态
list.add("张无忌");
list.add("周芷若");
list.add("小昭");
list.add("殷素素");
System.out.println(list); // [张无忌, 周芷若, 小昭, 殷素素]
// 2、给某个位置插入一个数据
list.add(1,"学Java的bb");
System.out.println(list);
// 3、根据索引删除数据。
System.out.println(list.remove(2));
System.out.println(list);
// 4、修改索引位置处的数据
list.set(2,"灭绝");
System.out.println(list);
// 5、根据索引取数据
System.out.println(list.get(2));
}
}
2.4.2 遍历方式
List集合支持的遍历方式:
- for循环(因为List集合有索引)
- 迭代器
- 增强for循环
- Lambda表达式
package com.itheima.d5_list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo2 {
public static void main(String[] args) {
// 目标:掌握List的遍历方式
// 1、创建一个List集合对象(一行经典代码)
List<String> list = new ArrayList<>();
list.add("金毛狮王");
list.add("谢逊");
list.add("白眉鹰王");
System.out.println(list);
// 一、for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// 二、迭代器
//while一次里面只能取一次it.next()
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String name = it.next();
System.out.println(name);
}
// 三、增强for循环
for (String name : list) {
System.out.println(name);
}
// 四、Lambda
list.forEach(s -> System.out.println(s));
//用方法引用来简化
list.forEach(System.out::println);
}
}
2.4.3 ArrayList集合的底层原理
ArrayList和LinkedList都是有序,可重复,有索引的,但是他们底层采用的数据结构不同,应用场景不同
删除和添加效率低只是相对而言的,实际上ArrayList我们还是很常用的
计算机的索引从0开始对于底层寻址的速度比较快
ArrayList的底层是一个动态扩容数组,其核心属性包括:
- elementData:存储元素的数组
- size:当前实际存储的元素数量(非数组长度),记录当前集合的大小,同时也是下一个元素的位置
ArrayList集合适合的应用场景:
- ArrayList适合:根据索引查询数据,比如根据随机索引取数据(高效),或者数据量不是很大时
- ArrayList不适合:数据量大的同时,又要频繁的进行增删操作!
2.4.4 LinkedList集合的底层原理
- 基于双链表实现的
LinkedList可以用来设计队列:先进先出,后进后出,只在链表的首尾进行操作
import java.util.LinkedList;
public class ListTest4 {
public static void main(String[] args) {
// 目标:掌握LinkedList的应用
// 1、做队列
LinkedList<String> queue = new LinkedList<>();
//入队
queue.addLast("第1个人");
queue.addLast("第2个人");
queue.addLast("第3个人");
queue.addLast("第4个人");
System.out.println(queue);
//出队
System.out.println(queue.removeFirst());
System.out.println(queue.removeFirst());
System.out.println(queue.removeFirst());
System.out.println(queue);
}
}
//2.做栈
LinkedList<String> stack = new LinkedList<>();
stack.addFirst("第1颗子弹");
stack.addFirst("第2颗子弹");
stack.addFirst("第3颗子弹");
stack.addFirst("第4颗子弹");
stack.addFirst("第5颗子弹");
System.out.println(stack);
// [第5颗子弹, 第4颗子弹, 第3颗子弹, 第2颗子弹, 第1颗子弹]
//出栈
System.out.println(stack.removeFirst());
System.out.println(stack.removeFirst());
System.out.println(stack.removeFirst());
System.out.println(stack);
// 第5颗子弹
// 第4颗子弹
// 第3颗子弹
// [第2颗子弹, 第1颗子弹]
2.4.5 手写链表
package com.itheima.d5_list;
import java.util.StringJoiner;
/**
*单链表
*/
public class MyLinkedList2<E> {
private int size = 0;
MyLinkedList2.Node<E> first; //定义头指针
//定义一个节点类:用于创建节点对象,封装节点数据和下一个节点对象的地址值
public static class Node<E> {
E item;
Node<E> next; // 下一个对象的地址。
public Node(E item, Node<E> next) {
this.item = item;
this.next = next;
}
}
//添加新节点的方法add()
public boolean add(E e) {
//维护单链表
//第一个节点,或者是后面的节点
//无论是第一个节点还是后面的节点都需要创建一个节点对象,封装这个数据
//新节点的下一个节点的地址值都为null
Node<E> newNode = new Node<>(e, null);
//判断这个节点是否是第一个节点
if (first == null) {
first = newNode;
} else {
//不是第一个节点,就要找到当前链表的最后一个元素
//如何找当前链表的最后一个元素,用一个临时变量接收first的值
//注意:在创建链表的过程中first节点始终不能改变。只能用临时变量接收它进行操作
Node<E> temp = first;
while (temp.next != null) {
temp = temp.next;
}
temp.next = newNode;
}
size++;
return true;
}
@Override
public String toString() {
//用StringJoiner拼接字符串时更高效
StringJoiner sb = new StringJoiner(", ", "[", "]");
Node<E> temp = first;
while (temp != null) {
//+ "" 是为了保证拼接的内容是字符串
sb.add(temp.item + "");
temp = temp.next;
}
return sb.toString();
}
public int size() {
return size;
}
}
class Test1{
public static void main(String[] args) {
MyLinkedList<String> list = new MyLinkedList<>();
list.add("java1");
list.add("java2");
list.add("java3");
list.add("java4");
list.add("java5");
list.add("java6");
list.add("java7");
list.add("java8");
list.add("java9");
list.add("java10");
list.add("java11");
System.out.println(list);
}
}
2.5 set集合
2.5.1 特点
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
public class SetDemo1 {
public static void main(String[] args) {
// 目标:了解Set家族的特点:无序,不重复,无索引。
//Set<String> set = new HashSet<>(); // 多态,一行经典代码。
Set<String> set = new LinkedHashSet<>(); // 有序,不重复,无索引。
set.add("张无忌");
set.add("张无忌");
set.add("朱九真");
set.add("周芷若");
set.add("周芷若");
set.add("赵敏");
set.add("小昭");
System.out.println(set); // [小昭, 周芷若, 赵敏, 张无忌, 朱九真]
}
}
2.5.2 HashSet集合的底层原理
package com.itheima.d6_set;
public class SetDemo2 {
public static void main(String[] args) {
// 目标:拿到对象的哈希值。
String name1 = "abc";
String name2 = "acB";
// 备注:不同对象的哈希值大概率不相同,但可能存在相同的情况。
System.out.println(name1.hashCode());//96354
System.out.println(name1.hashCode());//96354
System.out.println(name2.hashCode());//96352
}
}
哈希值其实就是一个随机数,不同对象的哈希值有可能会相同
HashSet集合的底层原理
- 基于哈希表实现
- 哈希表是一种增删查改数据,性能都较好的数据结构
哈希表
- JDK8之前,哈希表 = 数组 + 链表
- JDK8开始,哈希表 = 数组 + 链表 + 红黑树
用对象的哈希值对底层数组的长度求余
哈希表是一种增删查改数据性能都较好的结构,牺牲内存,只适合无序,不重复,无索引的业务。
默认加载因子:
- 在Java里大多数哈希表的默认加载因子是0.75(也存在特殊情况比如 IdentityHashMap 的默认加载因子为 0.666,而 EnumMap 则不使用加载因子)当哈希表中的条目数量超出了加载因子与当前容量的乘积时,哈希表就会进行扩容操作(即执行 resize)。
在上面的例子中就是0.75 * 16 = 12,当存储的元素超过12个之后,哈希表就会自动扩容为 32。
- 扩容操作会让哈希表的容量翻倍(即扩容为原来的两倍)同时重新计算所有键的哈希位置,这一过程也被称作 rehashing。
-
为什么默认值是 0.75
- 这一数值是时间和空间成本之间权衡的结果。
- 若加载因子较大,像设为 1,那么哈希表对空间的利用率会更高,不过哈希冲突发生的概率也会随之增加,这会导致查询性能下降。
- 若加载因子较小,例如 0.5,哈希冲突会减少,从而使查询速度更快,但这样会占用更多的空间,造成空间浪费。
使用红黑树的好处:
- 链表的问题:当发生哈希冲突时,传统的链表结构(每个槽位存储一个链表)在最坏情况下的查找时间复杂度为 O(n)(所有元素都在同一个链表中)。
- 红黑树的优势:当一个槽位中的元素数量超过阈值(默认为 8)且哈希表容量≥64 时,链表会转换为红黑树,此时查找、插入和删除操作的时间复杂度优化为 O(log n),避免了链表过长导致的性能退化。红黑树可以将元素铺开,性能更好,基于二分查找的算法。
-
自适应调整结构:当元素数量减少(例如删除操作后)且树的节点数少于阈值(默认为 6)时,红黑树会自动转换回链表,平衡空间和时间开销。
平衡二叉树任意两棵子树的左右高度差不超过1
任何一条路径下黑节点的个数是一样的
深入理解HashSet集合去重复机制
重写hashCode()和equals(),当我们向HashSet中添加一个新元素时,HashSet会先调用该元素的hasCode()方法,用对象中的元素来返回哈希值,如果两个对象的内容时一样的,返回的哈希值就是一样的。
equals() 的作用:equals() 方法用于确保当两个对象的内容相同时,它们被视为同一个对象。
有人可能会问,已经有了hashCode()方法,当对象的内容相等时,返回的哈希值是一样的,已经能判断出哈希表中重复的元素,为什么还要重写equals方法?
因为两个对象的哈希值相同,并不一定意味着他们相等,哈希值也会有所重复,这就需要重写equals()方法时,必须同时重写hashCode()方法,要保证两个具有相等哈希值的对象内容也是相同的,才能真正确定时重复的元素,从而保证集合中元素的唯一性。
2.5.3 LinkedHashSet集合的底层原理
2.5.4 TreeSet集合
package com.itheima.d6_set;
// 方法一:类实现Comparable接口,重写compareTo方法
public class Girl implements Comparable<Girl>{
private String name;
private char sex;
private int age;
private double height;
public Girl() {
}
public Girl(String name, char sex, int age, double height) {
this.name = name;
this.sex = sex;
this.age = age;
this.height = height;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
@Override
public String toString() {
return "Girl{" +
"name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
", height=" + height +
'}' + '\n';
}
@Override
public int compareTo(Girl o) {
return o.age - this.age >= 0 ? 1 : -1;
}
}
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import static java.lang.Double.*;
public class SetDemo5 {
public static void main(String[] args) {
//目标:TreeSet排序对象
//方式二:TreeSet集合自带比较器对象Comparator
// Set<Girl> set = new TreeSet<>(new Comparator<Girl>() {
// @Override
// public int compare(Girl o1, Girl o2) {
// return Double.compare(o2.getHeight(),o1.getHeight());
// }
// });//排序,不重复,无索引
//简化代码
Set<Girl> set = new TreeSet<>((o1, o2) -> Double.compare(o2.getHeight(),o1.getHeight()));
set.add(new Girl("赵敏",'女',21,169.5));
set.add(new Girl("刘亦菲",'女',34,167.5));
set.add(new Girl("李若彤",'女',26,168.5));
set.add(new Girl("张若男",'女',19,171.5));
set.add(new Girl("杨幂",'女',34,172.5));
System.out.println(set);
}
}
TreeSet集合对自定义类型的对象排序,有两种方式指定比较规则。
- 类实现Comoarable接口,重写比较规则
- 集合自定义Comparator比较器对象,重写比较规则