java面试题:
throw 和 throws 的区别? (1)throw
作用在方法内,表示抛出具体异常,由方法体内的语句处理; 一定抛出了异常;
(2)throws
作用在方法的声明上,表示抛出异常,由调用者来进行异常处理; 可能出现异常,不一定会发生异常;
1.Set集合
Set集合特点
- 无序:存取顺序不一致
- 不重复:可以去重
- 无索引:没有索引,不能使用for循环遍历
Set实现类
- HashSet:无序、不重复、无索引
- LinkedHashSet:有序、不重复、无索引
- TreeSet:排序、不重复、无索引
// Set集合特点 HashSet LinkedHashSet TreeSet
// HashSet 无序,不重复,无索引
// Set<String> set = new HashSet<>();
//LinkedHashSet 有序,不重复,无索引
// Set<String> set = new LinkedHashSet<>();
//TreeSet 排序,不重复,无索引
Set<String> set = new TreeSet<>();
set.add("java");
set.add("java");
set.add("mybatis");
set.add("redis");
set.add("redis");
set.add("mysql");
System.out.println(set);
2.HashSet底层原理
- HashSet集合底层采用哈希表存储数据
- 哈希表是一种对增删改查数据性能都比较好的结构
哈希表的组成
- jdk8之前,底层使用数组+链表组成
- jdk8之后,底层使用数组+链表+红黑树组成
jdk1.7版本的哈希表实现方法:
- 创建一个默认长度16的数组
- 根据元素的哈希值跟数组的长度求余,算出应存入的位置(哈希算法)
- 判断当前位置是否为null,如果是null直接存入
- 如果位置不为null,表示有元素,则调用equals方法比较
- 如果一样,则不存,如果不一样,则存入数组
- jdk7新元素占老元素位置,指向老元素
- jdk8中新元素挂在老元素下面
jdk1.8版本开始HashSet实现方法:
- 底层结构:哈希表(数组、链表、红黑树)
- 当挂在元素下面的数据过多时,查询性能降低,从jdk8开始后,当链表长度超过8时候,自动转换为红黑树,进一步提高了操作数据的性能
3.LinkedHashSet集合
LinkedHashSet是HashSet的一个子类,继承了HashSet的一些特性
特点
- 有序、不重复、无索引
- 存入顺序与取出顺序一致
- 原理:底层数据结构还是哈希表,但是每个元素额外多了一个双链表的机制记录存储顺序
底层通过双链表记录添加顺序,所以LinkedHashSet是有序的
3.TreeSet集合
特点
- 不重复、无索引、可排序
- 可排序:默认按照元素的从小到大排序
- TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好
- TreeSet集合一定要排序,可以将元素按照指定的规则进行排序
默认排序规则
- 数值类型:Integer、Double,官方默认按照从小到大进行排序
- 对于字符串类型:默认按照首字符编号升序排序
- 对于自定义类,TreeSet无法直接排序,需要我们自己制定排序规则
排序实例
Set<String> set = new TreeSet<>();
set.add("y");
set.add("a");
set.add("Y");
set.add("A");
set.add("你好");
System.out.println(set);
小写字母的ASCII编码要大于大写字母的ASCII编码,汉字的ASCII编码要大于字母的ASCII编码,所以大写字母排在前面,汉字排在后面
自定义类的排序方法
-
方法一:
让自定义类实现comparable接口,重写compareTo方法,制定比较规则 -
方法二:
TreeSet集合有参构造函数,可以设置Comparator接口对应的比较器对象,来制定比较规则
自定义排序实例
方法一:
定义一个商品类,实现Comparable接口的comparable方法进行比较。
- comparable返回1,表示当前对象大于比较对象
- comparable返回-1,表示当前对象小于比较对象
- comparable返回0,表示当前两个对象相同
这里的comparable方法不会去重,如果两个对象的价格相等,则规定当前对象大于比较的对象。
public class Produce implements Comparable<Produce>{
private String id;
private String name;
private Double price;
public Produce() {
}
public Produce(String id, String name, Double price) {
this.id = id;
this.name = name;
this.price = price;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Produce produce = (Produce) o;
return Objects.equals(id, produce.id) && Objects.equals(name, produce.name) && Objects.equals(price, produce.price);
}
@Override
public int hashCode() {
return Objects.hash(id, name, price);
}
@Override
public String toString() {
return "Produce{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", price=" + price +
'}';
}
/**
*
* @param o
* @return
*/
@Override
public int compareTo(Produce o) {
//根据价格进行比较
return this.price - o.price >= 0 ? 1 : -1;
}
}
Set<Produce> set1 = new TreeSet<>();
set1.add(new Produce("0001","苹果",5.0));
set1.add(new Produce("0002","香蕉",3.4));
set1.add(new Produce("0003","西瓜",1.2));
set1.add(new Produce("0004","黄瓜",3.4));
System.out.println(set1);
输出样例
方法二:
如果类中存在比较器,构造函数中也存在比较器,那么优先使用构造器的比较规则
Set<Produce> set1 = new TreeSet<>(new Comparator<Produce>() {
@Override
public int compare(Produce o1, Produce o2) {
return o1.getPrice() - o2.getPrice() >= 0 ? 1 : -1;
}
});
set1.add(new Produce("0001","苹果",5.0));
set1.add(new Produce("0002","香蕉",3.4));
set1.add(new Produce("0003","西瓜",1.2));
set1.add(new Produce("0004","黄瓜",3.4));
System.out.println(set1);
我们还可以通过lambda表达式将代码简写成一行
Set<Produce> set1 = new TreeSet<>((o1, o2) -> o1.getPrice() - o2.getPrice() >= 0 ? 1 : -1);
如果想要去重,我们可以使用Double包装类中的compare方法进行比较去重。
Set<Produce> set1 = new TreeSet<>(new Comparator<Produce>() {
@Override
public int compare(Produce o1, Produce o2) {
return Double.compare(o1.getPrice(),o2.getPrice());
}
});
总结
- 如果想要增删改查速度快,但是元素无序,不重复,无索引
- 使用HashSet
- 如果想要增删改查速度快,但是元素有序,不重复,无索引
- 使用LinkedHashSet
- 如果想要对对象进行排序
- 使用TreeSet