java集合常用功能与使用。
集合按照其存储结构可以分为两大类,单列集合Collection和双列集合Map:
1. 单列集合:
Collection:
子接口:List 、Set。
List:有索引,可存储重复的数据,存取有序(即怎么存、怎么取)。
Set:没有索引,不可存储重复的数据,存取无序。
Collection常用方法:
add、addAll、remove、removeAll、contains、containsAll、size、clear、isEmpty。
//泛型,可以约束集合存储数据的类型。
Collection<String> c1 = new ArrayList<>();
//add,添加元素
c1.add("a");
c1.add("b");
c1.add("c");
System.out.println(c1);
Collection<String> c2 = new ArrayList<>();
c2.add("e");
//将指定集合所有元素添加到当前集合。
c1.addAll(c2);
System.out.println(c1);
//删除指定元素
System.out.println(c1.remove("a"));
System.out.println(c1);
//判断集合是否包含指定元素
System.out.println(c1.contains("c"));
//判断集合中是否包含指定集合所有元素
System.out.println(c1.containsAll(c2));
//集合的长度
System.out.println(c1.size());
//将指定集合中所有元素从当前集合中删除
System.out.println(c1.removeAll(c2));
System.out.println(c1);
//清空集合
c1.clear();
System.out.println(c1);
//判断集合是否为空
System.out.println(c1.isEmpty());
List:
List接口继承了Collection接口中的所有方法,还增加了一些索引操作集合的特有方法。
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add(0,"c");//向指定索引添加数据,若索引不存在,会有异常
System.out.println(list);
List<String> list2 = new ArrayList<>();
list2.add("d");
list.addAll(1, list2);//将指定集合添加到当前集合指定索引位置。
System.out.println(list);
System.out.println(list.get(1));//获取指定索引元素
System.out.println(list.remove(0));//根据索引删除元素,返回被删除的元素
System.out.println(list);
System.out.println(list.set(0,"ff"));//返回被修改的元素
System.out.println(list);
System.out.println(list.indexOf("a"));//元素第一次出现位置
System.out.println(list.lastIndexOf("c"));//元素最后出现的位置
System.out.println(list);
List list3= list.subList(1,2);//获取指定索引范围元素.返回新的集合
System.out.println(list3);
ArrayList:
Arraylist大部分方法有父类Collection和List继承过来,add、get方法实现存取。
ArrayList特点:
允许插入重复数据。
插入的元素是有序的。
动态扩容。
非线程安全,异步。
基于动态数组的数据结构。
擅长随机访问
使用场景:
底层是数组结构实现的,数组有索引、查询速度比较快、增删比较慢。使用场景:如果大量的数据经常做查询的操作、优先使用ArrayList。
LinkedList:
ArrayList在查询时速度快,但元素增删慢,而LinkedList克服了这种局限性。LinkedList内部维护了一个双向循环链表,链表中每一个元素都用引用的方式记住前一个元素与后一个元素(即与前后元素形成双向引用),当插入、删除元素时,只需要修改这种引用关系即可。所以LinkedList对集合的增删有很高的效率,而在做查询操作没有ArrayList快,可根据场景合理使用不同的方法。
LinkedList<String> link = new LinkedList<>();
link.add("a");
link.add("b");
link.add("c");
link.add("d");
System.out.println(link);
link.addFirst("e");//添加元素到开头
System.out.println(link);
link.addLast("f");//添加数据到末尾
System.out.println(link);
System.out.println(link.getFirst());//获取第一个元素
System.out.println(link.getLast());//获取最后一个元素
link.removeFirst();//删除第一个元素
link.removeLast();//删除最后一个元素
System.out.println(link);
Iterator:
主要用于遍历集合中的所有元素,也称迭代器(而Collection、Map主要用于存储)。
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
/**
* boolean hasNext()//判断是否还有元素.
* next()//获取当前元素.
* remove()//删除当前元素.
*/
Iterator<String> it = list.iterator();
//不能在迭代时删除list元素,否则会引发并发异常,可通过迭代器对象操作
while (it.hasNext()){
String str = it.next();
if ("b".equals(str)){
it.remove();
}
}
foreach循环:
比for循环写法更加简洁,foreach也称增强for循环,可用于遍历数组或集合。
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
for (String str : list) {
System.out.println(str);
}
int[] arr ={1, 2, 3, 4, 5};
for (int i : arr) {
System.out.println(i);
}
Set集合:
Set和List都继承自Collection接口,与Collection方法基本一致,并没有进行扩充,但是比Collection更加严格,Set中的元素时无序的并且不重复(List是有序的、可重复的)。
Set的两个实现类:HashSet和TreeSet。
HashSet根据哈希值确当元素所在集合中的存储位置,具有良好的存取性能。
TreeSet以二叉树的方式存储元素,它可以实现对集合中的元素进行排序。
HashSet:
//没有索引、无序、不能重复(HashSet子类LinkedHashSet可以保证存取顺序)。
//根据对象哈希值计算存储位置。
//判断当前位置是否有数据,没有数据:直接存储,有数据:属性值相同不存储(属性值不相同以链表结构存储)
HashSet<String> hs = new HashSet<>();
hs.add("a");
hs.add("e");
hs.add("c");
hs.add("d");
hs.add("b");
hs.add("e");
for (String h : hs) {
System.out.println(h);
}
存储自定义对象时需要重写hashCode和equals、否则将会存储重复的对象。
案例:
学生类:
class Student {
String name;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//重写equals
@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);
}
//重写hashCode
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
调用:
HashSet<Student> hs = new HashSet<>();
//LinkedHashSet<Student> hs = new LinkedHashSet<>();//可保证存取顺序
Student stu1 = new Student("张三",21);
Student stu2 = new Student("张三",21);
Student stu3 = new Student("李四",22);
Student stu4 = new Student("王五",23);
hs.add(stu1);
hs.add(stu2);
hs.add(stu3);
hs.add(stu4);
for (Student h : hs) {
System.out.println(h);
}
TreeSet:
可以对集合中的元素进行排序。
基本使用:
TreeSet<Integer> ts = new TreeSet<>();
ts.add(4);
ts.add(2);
ts.add(3);
ts.add(1);
for (Integer t : ts) {
System.out.println(t);
}
存储自定义对象:
排序方式1:自然排序,自定义的类必须实现Comparable接口,并重写排序条件(不重写则可能会丢失部分数据)。
自定义类:
//实现Comparable
class Student implements Comparable<Student>{
String name;
int age;
//省略set、get和构造方法......
@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);
}
//重写compareTo方法
// 编写排序规则
//返回值:负数(向左存),0(不存储),整数(向右存)。
@Override
public int compareTo(Student o) {
//按年龄升序,this在后则按年龄降序
int result = this.age - o.age;
//次要条件(避免因为年龄相同对象丢失),如果年龄相同,按姓名排序
if (result == 0){
result = this.name.compareTo(o.name);
}
return result;
}
}
使用:
TreeSet<Student> ts = new TreeSet<>();
Student stu1 = new Student("a1",21);
Student stu2 = new Student("a3",24);
Student stu3 = new Student("a2",22);
Student stu4 = new Student("a0",22);
ts.add(stu1);
ts.add(stu2);
ts.add(stu3);
ts.add(stu4);
for (Student t : ts) {
System.out.println(t);
}
比较器方式排序:
//匿名内部类方式传对象,重写compare方法
TreeSet<Integer> ts = new TreeSet<>(new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer o2) {//o1要存的数据,o2已经存进去的数据
//o2 - o1降序,o1 - o2升序
int result = o1 - o2;
return result;
}
});
ts.add(4);
ts.add(2);
ts.add(3);
ts.add(1);
for (Integer t : ts) {
System.out.println(t);
}
2. 双列集合:
Map:
常用实现类:Hashtable 、HashMap、TreeMap。
Hashtable :最早期的双列集合,目前少用,但是子类Properties一直沿用。
HashMap : 基于哈希表的 Map 接口的实现。
TreeMap:不仅实现了Map接口,还实现了java.util.SortMap接口。
HashMap是非线程安全的,也就是说在多线程的环境下,可能会存在问题,而Hashtable是线程安全的。
Map接口是一种双列集合,每个元素都包含一个Key、value值(key的值不能重复、value的值可以重复),键值之间存在映射关系,访问元素时,只要指定了key,就能找到value。
常用实现类:Hashtable 、HashMap 、TreeMap、Properties、LinkedHashMap。
Map接口常用方法:
常用方法及遍历集合方式:
//泛型,Map是接口不能new,new实现类。
Map<String,String> m = new HashMap<>();
m.put("k1","a");//添加数据
m.put("k2","a");
m.put("k3","b");
m.put("k3","c");
m.put("k4","e");
System.out.println(m);
System.out.println(m.get("k2"));//获取值
String rm = m.remove("k4");//删除数据,返回被删除的值
System.out.println(rm);
System.out.println(m);
System.out.println(m.size());//获取集合长度
System.out.println(m.containsKey("k2"));//判断是否包含指定的key
System.out.println(m.containsKey("k5"));//判断是否包含指定的key
System.out.println(m.containsValue("a"));//判断是否存在指定的值
System.out.println(m.containsValue("f"));//判断是否存在指定的值
System.out.println(m);
Collection<String> c1= m.values();//获取所有的值,保存到单列集合
System.out.println(c1);
Collection<String> c2= m.keySet();//获取所有的key值,保存到单列集合
System.out.println(c2);
//遍历集合1
Set<String> ks= m.keySet();//获取所有的key值,保存到单列集合Set
for (String s : ks) {
System.out.println(m.get(s));
}
//遍历集合2
Set<Map.Entry<String, String>> entries = m.entrySet();//获取键值对对象,保存到Set集合。
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println("key:"+key+" value:"+value);
}
m.clear();//清空集合
System.out.println(m);
HashMap集合:
map集合中的一个实现类,比较常用。
没有重复键,键值无序。
没有提供特有方法,特点很多与Map一样。
使用子类LinkedHashMap保证存储顺序,其他特点与Map接口一样
//通过泛型指定键值类型
//HashMap<String,String> hm = new HashMap<>();
//使用LinkedHashMap可以保证存储顺序,其他特点与Map接口一样
LinkedHashMap<String,String> hm = new LinkedHashMap<>();
hm.put("k1","a");//添加数据
hm.put("k2","a");
hm.put("k3","b");
hm.put("k3","c");
hm.put("k4","e");
System.out.println(hm);
//遍历集合
Set<String> ks = hm.keySet();
for (String k : ks) {
System.out.println(hm.get(k));
}
//同样可以用Map的entrySet()方式遍历
TreeMap集合
特点:HashMap键值无序、不可重复,TreeMap可对集合中的元素进行排序。
使用:
/**
* 特点:HashMap键值无序、不可重复,TreeMap可对集合中的元素进行排序。
* 只能根据键值排序
* 1自然排序(默认自然升序排序,Integer、String默认已重写,自定义的类必须实现Comparable接口,并重写排序方法),与单列集合TreeSet写法类似。
* 2比较器排序,在构造器方法传递Comparable接口实现类对象,重写compare方法。
*/
TreeMap<Integer,String> tm = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
int result = o2 - o1;
return result;
}
});
tm.put(1,"b");
tm.put(3,"c");
tm.put(2,"a");
tm.put(4,"d");
System.out.println(tm);
Properties
Map中的一个集合Hashtable(早期的使用,使用与HashMap类似,但是HashTable是线程安全的,HashTable存取速度很慢,基本与HashMap取代),但是他的子类Properties至今仍很常用(例如IO流读取配置文件等)。
可以如下使用(但是实际应用场景一般用于IO流的配置文件操作)。
Properties prpo = new Properties();
prpo.put("username","username1");
prpo.put("password","password1");
Set<Object> ks = prpo.keySet();
for (Object k : ks) {
Object value = prpo.get(k);
System.out.println("k:"+k+"v:"+value);
}