本篇文章是一个学习java的笔记,概括集合中的 list ,Arraylist, HashMap, EnumMap, TreeMap, Properties, Set, Queue , PriorityQueue, Deque, Collections 的基本用法, 以及集合的各种重写方法手段,当个字典吧!
文章目录
集合
在Java中,如果一个Java对象可以在内部持有若干其他Java对象,并对外提供访问接口,我们把这种Java对象称为集合, 我们最开始了解的数组,其实也可以看作是一种集合。
java集合设计中存在二个特点,一是实现了接口和实现类相分离,例如,有序表的接口是
List
,具体的实现类有ArrayList
,LinkedList
等,二是支持泛型,我们可以限制在一个集合中只能放入同一种数据类型的元素,例如:public ArrayList<String> myList = new ArrayList<String>(); // 这个list只能存放string类型
因为数组存在一定的缺陷,并不能满足我们的编程要求。
- 数组初始化后大小不可变;
- 数组只能按索引顺序存取。
Java的java.util
包主要提供了以下三种类型的集合:
List
:一种有序列表的集合,例如,按索引排列的Student
的List
;Set
:一种保证没有重复元素的集合,例如,所有无重复名称的Student
的Set
;Map
:一种通过键值(key-value)查找的映射表集合,例如,根据Student
的name
查找对应Student
的Map
。
集合list:
在集合类中, list作为最基础的一种集合, 他是有序列表,但不同于数组, 它可以进行内存的自动扩张和收缩, 并且list将添加和删除的操作封装起来了,使我们操作集合更简单,而不用去关心集合中的元素是如何移动的。
关于list的接口, 常见的接口方法如下:
- 在末尾添加一个元素:
boolean add(E e)
- 在指定索引添加一个元素:
boolean add(int index, E e)
- 删除指定索引的元素:
int remove(int index)
- 删除某个元素:
int remove(Object e)
- 获取指定索引的元素:
E get(int index)
- 获取链表大小(包含元素的个数):
int size()
常见的list子类, 有 ArrayList 和 LinkedList , 但是我们常用的还是ArrayList
比较如下:
描述 | ArrayList | LinkedList |
---|---|---|
获取指定元素 | 速度很快 | 需要从头开始查找元素 |
添加元素到末尾 | 速度很快 | 速度很快 |
在指定位置添加/删除 | 需要移动元素 | 不需要移动元素 |
内存占用 | 少 | 较大 |
关于list的Tip:
-
list可以允许我们加入相同的值
-
list可以允许们加入null值
-
创建list可以使用list的接口of()方法, 根据指定元素快速生成, 但是不允许加入null值
-
遍历list常用 for each 方法
public static void main(String[] args){
// 常规方法创建list
ArrayList<Integer> list = new ArrayList<Integer>();
// 可以允许我们加入相同的值
list.add('1');
list.add('1');
// 可以允许我们加入null值
list.add(null);
// 使用of() 方式快捷生成集合 但是这种方式不能加入null值
ArrayList<String> mylist = mylist.of("hello", "world");
// 遍历list
for(Integer integer:list){
System.out.println(integer);
}
// 或者像数组一样遍历
for(int i=0;i<list.size(); i++){
System.out.println(list.get(i));
}
}
list集合与Array数组的相互转换
-
list转换array
调用 toArray() 方式
public class Main { public static void main(String[] args) { List<String> list = List.of("apple", "pear", "banana"); // 转换如下 String[] array = list.toArray(new String[list.size()]); for (String s : array) { System.out.println(s); } // 或者更简洁方式 String[] array = list.toArray(String[]::new); } }
-
array转换为list
调用 List.of() 方式
Integer[] array = {2, 2, 2};
ArrarList<Integer> list = ArrayList.of(arrar);
// 如果是用List 作为接口, 那么返回的list只是一个只读list, 操作它就会出错。
list中比较需重写equals方法:
list作为一个有序列表, 按照先后顺序将数值存放, 所以我们可以根据索引值去获取特定值。
List
还提供了boolean contains(Object o)
方法来判断List
是否包含某个指定元素。此外,int indexOf(Object o)
方法可以返回某个元素的索引,如果元素不存在,就返回-1
。
先看一个例子:
public class Main {
public static void main(String[] args) {
List<String> list = List.of("A", "B", "C");
// 简单测试
System.out.prinln(list.contains("A")); // True
// 如果传入一个新的实例
System.out.prinln(list.contains(new String("A"))); //True
// 结果还是 True
}
}
根据上面代码, 在不同实例中,却得到了相同的结果, 原因是list内部使用了equals() 去判断元素是否相同,因此,要正确使用List
的contains()
、indexOf()
这些方法,放入的实例必须正确覆写equals()
方法,否则,放进去的实例,查找不到。我们之所以能正常放入String
、Integer
这些对象,是因为Java标准库定义的这些类已经正确实现了equals()
方法, 所以如果自己创建了一个对象,那么就需要重写equals() 方法。
比如:
public class Main {
public static void main(String[] args) {
List<Person> list = List.of(
new Person("Xiao Ming", 90),
new Person("Xiao Hong", 98),
new Person("Bob", 50)
);
System.out.println(list.contains("Bob"));
}
}
class Person {
String name;
Integer score;
public Person(String name, Integer score) {
this.name = name;
this.score = score;
}
}
// 结果输出是false
如何正确的重写equals() 方法:
我们要注意这个方法要达到什么要求返回True, 比如上面代码, 当名字和分数相同,就返回True
所以我们这样编写:
public boolean equals(Object o) {
if (o instanceof Person) {
Person p = (Person) o;
return Objects.equals(this.name, p.name) && this.score == p.score;
}
return false;
}
把这个代码加到上面,就是这样的效果:
public class Main {
public static void main(String[] args) {
List<Person> list = List.of(
new Person("Xiao Ming", 90),
new Person("Xiao Hong", 98),
new Person("Bob", 50)
);
System.out.println(list.contains(new Person("Bob", 50)); // 比较的时候,传入一个泛型对象
}
}
class Person {
String name;
Integer score;
public Person(String name, Integer score) {
this.name = name;
this.score = score;
}
@Override
public boolean equals(Object o) {
if (o instanceof Person) { // 首先判断类型 确保不是null类型
Person p = (Person) o;
return Objects.equals(this.name, p.name) && this.score == p.score;
}
return false;
}
}
在List
中查找元素时,List
的实现类通过元素的equals()
方法比较两个元素是否相等,因此,放入的元素必须正确覆写equals()
方法,Java标准库提供的String
、Integer
等已经覆写了equals()
方法
编写equals()
方法可借助Objects.equals()
判断。
如果不在List
中查找元素,就不必覆写equals()
方法。
映射表Map:
在python中,我们知道有字典这样的键值对来达到映射的效果, 可以更快的查找特定的值, 但是在java中,也有Map,
Map
这种键值(key-value)映射表的数据结构,作用就是能高效通过key
快速查找value
(元素)。
比如在如下情况,我们查找指定的信息
package listTest;
import java.util.HashMap;
public class mapiter {
public HashMap<String, Student> map = new HashMap<>();
public mapiter() {
// 将"Xiao Ming"和Student实例映射并关联
map.put("Xiao Ming", new Student("Xiao Ming", 99));
}
public static void main(String[] args) {
mapiter m = new mapiter();
// 通过key查找并返回映射的Student实例
Student target = m.map.get("Xiao Ming");
// true,同一个实例
System.out.println(target.score);
// 99
Student another = m.map.get("Bob");
// 通过另一个key查找
System.out.println(another);
// 未找到返回null
}
}
class Student {
public String name;
public int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
}
关于map的tip
-
如果要判断某个 key 是否存在, 我们可以使用
boolean containsKey(K key)
方法 -
对map中put相同的key, 不会报错,但是后者会覆盖前者信息, 最好还是单个存在
-
map中不存在顺序之说, 没有顺序,只有映射关系
-
对于map来说, 遍历存在二种方式。
package listTest;
import java.util.HashMap;
import java.util.Map;
public class mapiter {
public HashMap<String, Student> map = new HashMap<>();
public mapiter() {
// 将"Xiao Ming"和Student实例映射并关联
map.put("Xiao Ming", new Student("Xiao Ming", 99));
map.put("Xiao Gang", new Student("Xiao Gang", 87));
map.put("Xiao Hong", new Student("Xiao Hone", 99));
}
public void fun(){
// 正常遍历方法
System.out.println("for each 遍历");
for(String s: map.keySet()){
String name = map.get(s).name;
int score = map.get(s).score;
System.out.println(name + " = " + score);
}
}
public void fun2(){
// 其他方式遍历
System.out.println("其他方式遍历");
for(Map.Entry<String, Student> entry:map.entrySet()){
String name = entry.getValue().name;
Integer score = entry.getValue().score;
System.out.println(name + " = " + score);
}
}
public static void main(String[] args) {
mapiter m = new mapiter();
m.fun();
m.fun2();
}
}
class Student {
public String name;
public int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
}
在Map
的内部,对key
做比较是通过equals()
实现的,这一点和List
查找元素需要正确覆写equals()
是一样的,即正确使用Map
必须保证:作为key
的对象必须正确覆写equals()
方法。
我们经常使用String
作为key
,因为String
已经正确覆写了equals()
方法。但如果我们放入的key
是一个自己写的类,就必须保证正确覆写了equals()
方法,并且我们还要正确的编写 hashCode() 方法,因为 key计算索引的方式就是调用
key对象的
hashCode()方法,它返回一个
int整数。
HashMap正是通过这个方法直接定位
key对应的
value的索引,继而直接返回
value,所以如果是自己写的类, 就必须重写这二个方法。
值得一提的是, 实际上HashMap
初始化时默认的数组大小只有16, 当数据达到了上限, HashMap就会自动扩容, 我们也可以指定map容量
HashMap<String, Integer> map = new HashMap<>(10000);
重写方法
class Student {
public String name;
public int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
// 重写equals()
@Override
public boolean equals(Object obj) {
if (obj instanceof Student){
Student st = (Student) obj;
return Objects.equals(this.name, st.name) && this.score == st.score;
}
return false;
}
// 重写hashCode()
@Override
public int hashCode() {
return Objects.hash(name, score);
}
// 必要的时候,还可以重写tostring()
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
}
枚举 EnumMap
HashMap
是一种通过对key计算hashCode()
,通过空间换时间的方式,直接定位到value所在的内部数组的索引,因此,查找效率非常高, 但是如果我们的key他是 enum 类型, 其实在这里,我们就可以使用 Java函数库中中的 EnumMap , 它在内部以一个非常紧凑的数组存储value,并且根据enum
类型的key直接定位到内部数组的索引,并不需要计算hashCode()
,不但效率最高,而且没有额外的空间浪费。
代码如下:
public void fun3() {
// 枚举对象 泛型擦拭
Map<DayOfWeek, String> map = new EnumMap<>(DayOfWeek.class);
map.put(DayOfWeek.MONDAY, "星期一");
map.put(DayOfWeek.TUESDAY, "星期二");
map.put(DayOfWeek.WEDNESDAY, "星期三");
map.put(DayOfWeek.THURSDAY, "星期四");
map.put(DayOfWeek.FRIDAY, "星期五");
map.put(DayOfWeek.SATURDAY, "星期六");
map.put(DayOfWeek.SUNDAY, "星期日");
for (DayOfWeek dayOfWeek : map.keySet()) {
String day = map.get(dayOfWeek);
System.out.println(dayOfWeek + "是" + day);
}
System.out.println(DayOfWeek.WEDNESDAY + "是" + map.get(DayOfWeek.WEDNESDAY));
}
排序 TreeMap
我们知道对于map来说, 他是没有顺序而言的, 是一种空间换时间的映射表, 但实际上还有一个map它可以实现sort排序 功能的, 就是SorteMap , 但是实现类是TreeMap。
┌───┐
| Map |
└───┘
▲
┌────┴─────┐
│ │
┌───────┐ ┌─────────┐
│HashMap | │ SortedMap │
└───────┘ └─────────┘
▲
│
┌─────────┐
│ TreeMap │
└─────────┘
比如我们看一个例子:
当key是String 或者 Integer 类的时候, 这个时候默认是升序排列,因为String
、Integer
这些类已经实现了Comparable
接口,因此可以直接作为Key使用
public class Main {
public static void main(String[] args) {
Map<String, Integer> map = new TreeMap<>();
map.put("orange", 1);
map.put("apple", 2);
map.put("pear", 3);
for (String key : map.keySet()) {
System.out.println(key + map.get(key));
}
}
}
// 最后输出 apple 2, orange 1, pear 3
但是如果我们的类自己编写的, 或者我们想改变排序方式呢? 怎么重写?
要实现 Comparator<>() 接口 具体实现,如下:
// 关于 object.compareTo(object) 函数
// 如果前者大于后者 返回 大于0的数
// 如果前者等于后者 返回0
// 如果前者小于后者 返回小于0的数
public void fun4() {
Map<Student, Integer> map4 = new TreeMap<>(new Comparator<Student>() {
// @Override // 默认升序排列
// public int compare(Student o1, Student o2) {
// return o1.name.compareTo(o2.name);
// }
@Override // 重写 降序
public int compare(Student o1, Student o2) {
if (o1.name.equals(o2.name)) {
return 0;
} else if (o1.name.compareTo(o2.name) > 0) {
return -1;
} else {
return 1;
}
}
});
map4.put(new Student("Xiao Ming", 99), 1);
map4.put(new Student("Xiao Gang", 87), 2);
map4.put(new Student("Xiao Hone", 99), 3);
// 遍历
for (Student student : map4.keySet()) {
String name = student.name;
System.out.println(name + map4.get(student));
}
}
class Student {
public String name;
public int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
}
配置文件Properties:
很多时候,我们需要去读写配置文件,这些配置文件的特点就是 key-value 一般来说都是string-string 的类型, 所以我们完全是可以用 HashMap<String, String> 去实现这样功能
我们使用 Properties 去读取配置文件, 关于配置文件,
Java默认配置文件以.properties
为扩展名,所以我们要在当前目录下新建一个 setting.properties 的文件, 然后每行以key=value
表示,以#
课开头的是注释。如下是最简单的配置文件:
# setting.properties
last_open_file=hello.txt
auto_save_interval=60
username=me
然后怎么读取这个配置文件 方法如下:(这个是调用文件流)
String f = "D:\\java\\java代码\\package\\listTest\\setting.properties";
Properties props = new Properties();
props.load(new java.io.FileInputStream(f)); //导入一个文件流
String filepath = props.getProperty("last_open_file");
String interval = props.getProperty("auto_save_interval", "120");
System.out.println(filepath);
具体步骤分三步:
- 创建
Properties
实例; as: Properties props = new Properties(); - 调用
load()
读取文件; as: props.load(inputSteam) 可以文件流 字节流 也可以资源流 - 调用
getProperty()
获取配置。
我们试试一个字节流的调用方法: (使用字节流,要注意每一个key-value 要有换行)
public void fun5() throws IOException {
/*读取字节流*/
String settings = "# test \n course=Java \n last_open_date=2019-08-07T12:35:01" +
"\n username=shalouzaixyua";
ByteArrayInputStream input = new ByteArrayInputStream(settings.getBytes("UTF-8"));
// 创建一个Properties实例
Properties props = new Properties();
// 调用load读取一个字节流
props.load(input);
// 调用getProperty获得配置文件
System.out.println("course: " + props.getProperty("course"));
System.out.println("last_open_date: " + props.getProperty("last_open_date"));
System.out.println("last_open_file: " + props.getProperty("last_open_file"));
System.out.println("auto_save: " + props.getProperty("auto_save", "60"));
System.out.println("The author:" + props.getProperty("username"));
// 写入一个新的配置文件
props.setProperty("id", "888888888");
// 重新读取这个配置文件
System.out.println("The id:" + props.getProperty("id"));
}
集合Set:
我们知道map是用来存储不重复的key-value 映射对, 那如果我们只是想保存不重复的key呢? 我们可以直接用Set,它可以用于存储不重复的元素集合,类似python中的set集合。
主要方法如下:
- 将元素添加进
Set<E>
:boolean add(E e)
- 将元素从
Set<E>
删除:boolean remove(Object e)
- 判断是否包含元素:
boolean contains(Object e)
简单例子:
Set<String> set = new HashSet<>();
set.add("abc");
set.remove("abc");
set.contains("abc"); // false
因为set只是存储key的一个集合,所以我们可以用这个达到去重的效果, 这里要注意一点,放入set的key类都必须正确实现equals() 方法 和 hashcode() 方法。
我们的set接口用一张图表示:
Set
|
________________
| |
HashSet SorteSet
|
TreeSet
HashSet
是无序的,因为它实现了Set
接口,并没有实现SortedSet
接口;TreeSet
是有序的,因为它实现了SortedSet
接口。
如果我们随意的输出Hashset中的元素
public class Main {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("apple");
set.add("banana");
set.add("pear");
set.add("orange");
for (String s : set) {
System.out.println(s);
}
}
}
// 顺序是随意的 不确保
// banana pear apple orange
如果我们输出TreeSet中的元素
public class Main {
public static void main(String[] args) {
Set<String> set = new TreeSet<>();
set.add("apple");
set.add("banana");
set.add("pear");
set.add("orange");
for (String s : set) {
System.out.println(s);
}
}
}
// apple banana orange pear A-Z的升序
// 如果要更改排序 需要重写tree中的compare方法
练习二种去重方法:
package listTest;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
public class Set {
public static void main(String[] args) throws IOException {
List<Message> received = List.of(
new Message(1, "Hello!"),
new Message(2, "你在干嘛?"),
new Message(2, "你在干嘛啊啊?"),
new Message(3, "去哪吃饭?"),
new Message(3, "去哪吃饭?"),
new Message(4, "滚")
);
List<Message> displayMessages = process(received); // 调用函数
for (Message message : displayMessages) {
System.out.println(message.text);
}
fun();
}
static List<Message> process(List<Message> received) {
// TODO: 第一种方式
// HashSet<Integer> set = new HashSet<>();
// ArrayList<Message> newList = new ArrayList<>();
// for(Message message:received){
// // 如果不存在 就放得进去
// if(set.add(message.sequence)){
// newList.add(message);
// }
// }
//
// return newList;
// }
// reveived 是一个包含重复sequence的集合list
TreeSet<Message> set = new TreeSet<>(new Comparator<Message>() {
@Override
//TODO: 按照sequence 达到去重效果 第二种方式
public int compare(Message o1, Message o2) {
return o1.sequence > o2.sequence ? 1 : (o1.sequence < o2.sequence ?
-1 : 0);
}
});
for(Message message:received){
set.add(message);
}
return new ArrayList<Message>(set);
}
}
class Message {
public final int sequence;
public final String text;
public Message(int sequence, String text) {
this.sequence = sequence;
this.text = text;
}
@Override
public String toString() {
return sequence + ":" + text;
}
}
队列Queue:
队列(
Queue
)是一种经常使用的集合。Queue
实际上是实现了一个先进先出(FIFO:First In First Out)的有序表。它和List
的区别在于,List
可以在任意位置添加和删除元素,而Queue
只有两个操作:
- 把元素添加到队列末尾;
- 从队列头部取出元素。
queue有如下方法:
int size()
:获取队列长度;boolean add(E)
/boolean offer(E)
:添加元素到队尾;E remove()
/E poll()
:获取队首元素并从队列中删除;E element()
/E peek()
:获取队首元素但并不从队列中删除。
除了size() 只有一种方式, 其他方法都有二种, 二种的操作都是一样的, 但是对异常的处理情况不一样。
方法 | throw Exception | 返回false或null |
---|---|---|
添加元素到队尾 | add(E e) | boolean offer(E e) |
取队首元素并删除 | E remove() | E poll() |
取队首元素但不删除 | E element() | E peek() |
这三个都会抛出异常 | 不会抛出异常 |
这些我们根据源码得到理解,附上一段源码,理解一下
/**
* Retrieves, but does not remove, the head of this queue. This method
* differs from {@link #peek peek} only in that it throws an exception
* if this queue is empty.
*
* @return the head of this queue
* @throws NoSuchElementException if this queue is empty
*/
E element(); // 上面是对element 的描述
/**
* Retrieves, but does not remove, the head of this queue,
* or returns {@code null} if this queue is empty.
*
* @return the head of this queue, or {@code null} if this queue is empty
*/
E peek(); // 上面是对peek 的描述
简单的实现方法:
public class queue {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();
// 二种添加方法 向尾部添加
queue.add("I am first means ");
queue.offer("I am second means");
// 二种取出但不删除 从头部取出 所以每次都是头部信息
String s1 = queue.element();
String s2 = queue.peek();
System.out.println(s1 + "\n" + s2);
// 二种取出删除方法, 从头部删除
queue.remove();
queue.poll();
// 获取长度 全删掉了 没了
System.out.println(queue.size());
}
}
优先队列PriorityQueue:
之前使用的Queue队列。他是严格规定 “先进先出” 的规则,没有优先权限, 这会影响我们一些实际开发, 比如存在VIP用户的基础上, 我们就需要使用PriorityQueue 优先队列,来处理这件事情了。
先来看看一个简单的队列方法:
public class Main {
public static void main(String[] args) {
Queue<String> q = new PriorityQueue<>();
// 添加3个元素到队列:
q.offer("apple");
q.offer("pear");
q.offer("banana");
System.out.println(q.poll()); // apple
System.out.println(q.poll()); // banana
System.out.println(q.poll()); // pear
System.out.println(q.poll()); // null,因为队列为空
}
}
// 默认String类实现了 Comparable 接口, 排序默认升序
那如果我们放入的元素没有实现 Comparable接口呢,PriorityQueue 允许我们提供一个 comparator 对象来判断优先级,这里有一个例子:
package listTest;
import java.util.*;
public class queue {
public static void main(String[] args) {
Queue<User> q = new PriorityQueue<>(new UserComparator());
// 添加3个元素到队列:
q.offer(new User("Bob", "A10"));
q.offer(new User("Alice", "A2"));
q.offer(new User("lucy", "A6"));
q.offer(new User("Boss", "V1"));
System.out.println(q.poll());
System.out.println(q.poll());
System.out.println(q.poll());
System.out.println(q.poll());
System.out.println(q.size());
}
}
class UserComparator implements Comparator<User> {
@Override
public int compare(User u1, User u2) {
if (u1.number.charAt(0) == u2.number.charAt(0)) {
// 如果两人的号都是A开头或者都是V开头,比较号的大小:
if (u1.number.length() == u2.number.length()) {
return u1.number.compareTo(u2.number);
} else {
return (u1.number.length() > u2.number.length() ? 1 : -1); // 如果长度不相同 返回小号
}
}
if (u1.number.charAt(0) == 'V') {
return -1;
// u1的号码是V开头,优先级高:
} else {
return 1;
}
}
}
class User {
public final String name;
public final String number;
public User(String name, String number) {
this.name = name;
this.number = number;
}
@Override
public String toString() {
return "现在是客户:" + name + "// 权限为:" + number;
}
}
小提示:
PriorityQueue
实现了一个优先队列:从队首获取元素时,总是获取优先级最高的元素。
PriorityQueue
默认按元素比较的顺序排序(必须实现Comparable
接口),也可以通过Comparator
自定义排序算法(元素就不必实现Comparable
接口)。
双向队列 Deque:
不管是Queue队列,还是PriorityQueue 优先队列, 他们都遵循一个原则, 只能从尾部向队列进行增加,从头部取出元素,但是我们可以从Queue中派生出一个 Deque 双向队列,它可以允许我们从二端添加元素,并且可以从二段取出元素。
可以看一下Deque的简单使用:
public static void main(String[] args) {
Deque<String> deque = new LinkedList<>();
// 向二头加入元素
deque.offerFirst("first");
deque.offerLast("last");
// 向二头删除元素
System.out.println(deque.pollFirst());
System.out.println(deque.pollLast());
// 队列长度
System.out.println(deque.size());
}
我们来看一下 Deque 和 Queue的 一些区别:
Means | Queue | Deque |
---|---|---|
添加元素到队尾 | add(E e) / offer(E e) | addLast(E e) / offerLast(E e) |
取队首元素并删除 | E remove() / E poll() | E removeFirst() / E pollFirst() |
取队首元素但不删除 | E element() / E peek() | E getFirst() / E peekFirst() |
添加元素到队首 | 无 | addFirst(E e) / offerFirst(E e) |
取队尾元素并删除 | 无 | E removeLast() / E pollLast() |
取队尾元素但不删除 | 无 | E getLast() / E peekLast() |
Collections类:
Collections 给我们提供了一些方法. 比如对集合的排序,扰乱等。
排序
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("pear");
list.add("orange");
// 排序方法
Collections.sort(list);
// 排序后:
System.out.println(list);
}
}
提到排序,这里需要继续排序扩展,一般我们使用的是Arrays.sort() 对数组进行排序, 但是这个排序默认升序, 如果需要进行改写排序规则,怎么办呢?
- 第一种 使用 Collections.reverseOrder() 方法
public static void main(String[] args) {
Integer[] mylist = {2, 10, 4, 1, 3, 5};
Arrays.sort(mylist, Collections.reverseOrder());
System.out.println(Arrays.toString(mylist));
}
- 第二种 重写 Comparator接口中的compare方法
public static void main(String[] args) {
Integer[] mylist = {2, 10, 4, 1, 3, 5};
// 创建一个Comparator 类
Comparator cmp = new CMP();
Arrays.sort(mylist, cmp);
System.out.println(Arrays.toString(mylist));
}
}
class CMP implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return o1 > o2 ? -1 : 1;
}
}
洗牌打乱
Collections 提供了一个 洗牌算法 shuffle() 可以把集合类的顺序随机打乱。 如下:
public class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i=0; i<10; i++) {
list.add(i);
}
// shuffle 算法之后
Collections.shuffle(list);
// 洗牌后:
System.out.println(list);
}
}
本篇文章是一个学习java的笔记,概括集合中的 list ,Arraylist, HashMap, EnumMap, TreeMap, Properties, Set, Queue , PriorityQueue, Deque, Collections 的基本用法, 以及集合的各种重写方法手段,当个字典吧!