类集框架
一、Collection 集合接口
当前主要分类两个子接口,允许重复的List接口和不允许重复的Set接口
1. List接口
import java.util.List;
public class javaDemo{
public static void main(String[] args) throws Exception{
List<String> all = List.of("bob","john","tom");
Object[] result = all.toArray();
for (Object t:result){
System.out.println(t+"、");
}
}
}
使用List接口进行开发时,主要使用其子类进行实例化,常用子类有ArrayList, Vector, LinkedList
1.1 ArrayList
import java.util.ArrayList;
import java.util.List;
public class javaDemo{
public static void main(String[] args) throws Exception{
List<String> all = new ArrayList<>();
all.add("bob");
all.add("tom");
all.add("john");
System.out.println(all.get(1));
System.out.println(all);
all.remove("bob"); // 删除bob元素
all.isEmpty(); // 集合是否为空
all.contains("bob"); // 是否包含bob元素
all.size(); // 集合长度
all.forEach((str)->{ // 打印方法
System.out.println(str+"、");
});
}
}
上面程序实现了打印,但是是利用每个类中的toString()方法实现的,也就是需要类中实现有toString方法,对自定义的类不利,因为自定义类中未必实现了toString()
ArrayList保存自定义类对象
由于String是一个完善的类,因此在类集操作时可以保存任意类型的数据,这也就包括了开发者自己定义的类。为了保证集合中的contains()
和remove()
两个方法的正确执行,需要覆写equals()
方法
import java.util.ArrayList;
import java.util.List;
class Member{
private String name;
private int age;
public Member(String name, int age){
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o){
return true;
}
if(o == null){
return false;
}
if (!(o instanceof Member)){
return false;
}
Member mem = (Member) o;
return this.name.equals(mem.name) && this.age == mem.age;
}
public String toString(){
return "姓名:"+ this.name+"、年龄:"+this.age;
}
}
public class javaDemo{
public static void main(String[] args) throws Exception{
List<Member> all = new ArrayList<Member>();
all.add(new Member("BOB",13));
all.add(new Member("TOM", 15));
all.add(new Member("JOHN", 22));
all.remove(new Member("TOM", 15));
all.forEach(System.out::println);
}
}
ArrayList使用了数组Array保存数据,如果数据超过限度,该类自动进行扩展,将旧数组中的数据复制到新数组中,最大限制为private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
如果频繁进行数组的扩展,会造成大量的内存垃圾,因此使用该类的时候,需要对集合大小进行合理的估算,不要频繁改动
无参构造:public ArrayList(),使用空数组进行初始化,第一次使用时开辟长度为10的空间
有参构造:public ArrayList(int initialCapacity),开辟空间,为0则使用无参构造,为负数,抛出异常
1.2 LinkedList
实现方法与ArrayList一致,但是其是建立在链表形式的List接口标准,进行添加元素时,不像ArrayList那样频繁的进行复制开辟新数组,而是可以直接以O(1)的复杂度插入数据
但在根据索引获取元素的时候,复杂度为O(n),比Array的O(1)差了许多
1.3 Vector
和ArrayList类实现一致,唯一的区别是Vector的操作方法都用了synchronized进行同步处理,因此是线程安全的,但是性能会降低,所以Vector可以用在多线程并发访问时
2 Set接口
如果调用Set.of()
方法时出现了重复元素,会抛出异常
其有两个常用子类HashSet
和TreeSet
2.1 HashSet
不允许保存重复元素,且以散列(无序)方式进行存储
import java.util.HashSet;
import java.util.Set;
public class javaDemo{
public static void main(String[] args) throws Exception{
Set<String> all = new HashSet<>();
all.add("bob");
all.add("tom");
all.add("john");
System.out.println(all);
}
}
输出数据以无序格式存放,不会按照添加顺序打印出来,且重复元素会去除
2.1.1 LinkedHashSet
import java.util.LinkedHashSet;
import java.util.Set;
public class javaDemo{
public static void main(String[] args) throws Exception{
Set<String> all = new LinkedHashSet<>();
all.add("bob");
all.add("tom");
all.add("tom");
all.add("john");
System.out.println(all);
}
}
HashSeet的问题在于无序存储,所以LinkedHashSet实现了基于链表的数据存储,保留了顺序,且不允许重复元素
2.2 TreeSet
可以使集合保存的数据进行有序排列
import java.util.Set;
import java.util.TreeSet;
public class javaDemo{
public static void main(String[] args) throws Exception{
Set<String> all = new TreeSet<>();
all.add("bibibi");
all.add("tom");
all.add("tom");
all.add("john");
System.out.println(all);
}
}
输出:[bibibi, john, tom]
TreeSet类实现有序数据存储是根据Comparable接口实现的,并且根据接口中的compareTo()
方法来判断重复元素,所以使用TreeSet类存储自定义类对象的时候,必须实现Comparable接口,覆写comareTo方法时需要进行类中全部属性的比较,否则会出现部分属性相同时被误判为同一对象,导致重复元素判断失败
import java.util.Set;
import java.util.TreeSet;
class Member implements Comparable<Member>{
private String name;
private int age;
public Member(String name, int age){
this.name = name;
this.age = age;
}
// 覆写comareTo方法,并且比较所有的属性是否相同
@Override
public int compareTo(Member mem){
if (this.age > mem.age){
return -1;
} else if(this.age < mem.age){
return 1;
} else{
return this.name.compareTo(mem.name);
}
}
public String toString(){
return "姓名:"+ this.name+"、年龄:"+this.age;
}
}
public class javaDemo{
public static void main(String[] args) throws Exception{
Set<Member> all = new TreeSet<Member>();
all.add(new Member("BOB",13));
all.add(new Member("TOM", 15));
all.add(new Member("JOHN", 22));
// all.remove(new Member("TOM", 15));
all.forEach(System.out::println);
}
}
2.2.1 重复元素消除(待处理)
二、Collection集合输出
collection接口提供了toArray方法将集合保存的数据转为对象数组返回,用户可以利用循环进行读取,但性能不佳。在类集框架中提供了4种方式:Iterator, ListIterator, Enmueration, foreach
1. Iterator
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class javaDemo{
public static void main(String[] args) throws Exception{
Set<String> all = new TreeSet<>();
all.add("bibibi");
all.add("tom");
all.add("tom");
all.add("john");
Iterator<String > iter = all.iterator();
while (iter.hasNext()){ //判断是否有下一个值
String str = iter.next(); // 接受任意类型的数据
System.out.println(str+"、");
}
}
}
迭代输出中的remove()
方法,不要使用Collection中提供的remove方法,而应该使用iterator.remove()
方法,否则会出现并发访问异常java.util.ConcurrentModificationException
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class javaDemo{
public static void main(String[] args) throws Exception{
Set<String> all = new TreeSet<>();
all.add("bibibi");
all.add("tom");
all.add("tom");
all.add("john");
Iterator<String > iter = all.iterator();
while (iter.hasNext()){
String str = iter.next();
if (str.equals("john")){
iter.remove();
}else {
System.out.println(str+"、");}
}
}
}
2. ListIterator
Iterator实现了单向迭代操作,而ListIterator则提供了双向迭代操作,此接口为Iterator的子接口,仅能对List类进行实例化,而Iterator可以对Collection进行实例化
该类没有提供remove方法
import java.util.*;
public class javaDemo{
public static void main(String[] args) throws Exception{
List<String> all = new ArrayList<>();
all.add("helen");
all.add("tom");
all.add("john");
ListIterator<String > iter = all.listIterator();
while (iter.hasNext()){
String str = iter.next();
System.out.println(str+"、");
}
while (iter.hasPrevious()){
String pre = iter.previous();
System.out.println(pre+"、");
}
}
}
使用双向迭代的时候,必须先从前向后迭代,再从后向前迭代
3. Enmueration
该类主要针对Vector类的输出进行处理,其没有提供remove方法
import java.util.*;
public class javaDemo{
public static void main(String[] args) throws Exception{
Vector<String> all = new Vector<>(); // 只使用Vector类
all.add("helen");
all.add("tom");
all.add("john");
Enumeration<String > enu = all.elements();
while (enu.hasMoreElements()){
String str = enu.nextElement();
System.out.println(str+"、");
}
}
}
3. foreach
使用foreach实现输出
import java.util.*;
public class javaDemo{
public static void main(String[] args) throws Exception{
List<String> all = new ArrayList<>();
all.add("helen");
all.add("tom");
all.add("john");
for (String s: all){
System.out.println(s);
}
}
}
实现自定义类的输出,需要实现Iterable接口,这样就鞥呢利用foreach实现输出操作
三、Map集合
存储结构为(key == value)
import java.util.*;
public class javaDemo{
public static void main(String[] args) throws Exception{
Map<String, Integer> map = Map.of("one",1, "two",2); // map的格式为<K, V>
System.out.println(map);
}
}
这种设计方法比较死板,实际使用中主要使用其子类进行实例化,常见的有HashMap、LinkedHashMap、HashTable、TreeMap
1. HashMap
基于散列形式实现Map集合
import java.util.*;
public class javaDemo{
public static void main(String[] args) throws Exception{
Map<String, Integer> map = new HashMap<>();
map.put("funny", 2);
map.put("tom",12);
map.put("tom",222); // key重复则会覆盖前值
map.put("scc",null);
map.put(null, 2);
System.out.println(map.get("funny"));
System.out.println(map.get(null)); // 即便key为null,也会输出其key=2
System.out.println(map.get("tom"));
}
}
Collection设置完内容的目的是输出,Map的目的是查找
2. LinkedHashMap
基于链表的形式实现了Map集合,实现了有序集合
import java.util.*;
public class javaDemo{
public static void main(String[] args) throws Exception{
Map<String, Integer> map = new LinkedHashMap<>();
map.put("funny", 2);
map.put("tom",12);
map.put("scc",null);
map.put(null, 2);
System.out.println(map);
}
}
3. Hashtable
HashMap允许实现异步操作(非线程安全),HashMap允许保存null数据
Hashtable属于同步操作(线程安全),不允许保存null数据,否则会抛出NullPointerException
4. TreeMap
同样使用Comparable接口实现内容的有序存储
String类中实现了Comparable接口,所以可以进行排序
import java.util.*;
public class javaDemo{
public static void main(String[] args) throws Exception{
Map<String, Integer> map = new TreeMap<>();
map.put("funny", 2);
map.put("tom",12);
map.put("clarie",24);
System.out.println(map)
}
}
5. Map.Entry内部接口
import java.util.*;
public class javaDemo{
public static void main(String[] args) {
Map.Entry<String, Integer> entry = Map.entry("ONE", 1);
System.out.println(entry.getKey());
System.out.println(entry.getValue());
System.out.println(entry.getClass().getName());
}
}
输出:
ONE
1
java.util.KeyValueHolder
6. Iterator输出Map集合
要输出Map集合内容,Map接口中保存的数据是多个Map.Entry接口封装的二元偶对象,所以采用下面步骤实现Map集合的迭代输出
- 使用Map接口中的enrtySet()方法,将Map集合变为Set结合
- 取得了Set集合的接口后,可以利用Iterator()方法取得Iterator的实例化对象
- 使用Iterator迭代找到每一个Mao.Entry对象,并进行key和value的分离
Map集合中的都是[ Map.Entry,Map.Entry,Map.Entry ]
Collection集合中都是[ 对象,对象,对象 ]
import java.util.*;
public class javaDemo{
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("one", 1);
map.put("two" ,2);
Set<Map.Entry<String, Integer>> set = map.entrySet();
Iterator<Map.Entry<String, Integer>> iter = set.iterator();
while (iter.hasNext()){// 使用iterator接口实现输出
Map.Entry<String, Integer> me = iter.next(); // 使用类型为Map.Entry的me变量存储iter的输出
System.out.println(me.getKey()+" == "+me.getValue());
}
for (Map.Entry<String, Integer> entry:set){// 使用foreach输出
System.out.println(entry.getKey()+" == "+entry.getValue());
}
}
}
7. 自定义key类型
覆写hashCode()和equals()方法
四、Stack栈
栈是有序的数据结构,采用先进后出的存储模式,开发者只能进行栈顶操作,主要有入栈和出栈两种操作
import java.util.*;
public class javaDemo{
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
stack.push("A"); // 入栈
stack.push("B");
stack.push("C");
System.out.println(stack.peek()); // 查看栈顶 输出:C
System.out.println(stack.search("B")); // 输出:2
System.out.println(stack.pop()); // 出栈并删除栈顶元素 输出:C
System.out.println(stack.pop()); // 输出:B
}
}
五、Queue队列
import java.util.*;
public class javaDemo{
public static void main(String[] args) {
Queue<String> queue = new PriorityQueue<>();
queue.add("A");
queue.add("B");// 添加元素
queue.offer("C");// 添加元素
System.out.println(queue.peek()); // 查看队首 输出 A
System.out.println(queue.poll()); // 删除元素并输出
System.out.println(queue.poll());
}
}
为了实现能在队首和队尾操作元素的,java实现了Queue的子类Deque
import java.util.*;
public class javaDemo{
public static void main(String[] args) {
Deque<String> deque = new LinkedList<>();
deque.addLast("A"); // 添加到队尾
deque.addFirst("B"); // 添加到队首
deque.offerFirst("C"); // 添加到队首
System.out.println(deque.peekFirst()); // 查看队首元素
System.out.println(deque.removeFirst()); // 删除队首元素
System.out.println(deque.pollFirst()); // 删除队首元素并输出
System.out.println(deque.pollLast()); // 删除队尾元素并输出
}
}
六、Properties属性操作
该类主要用来处理字符串的输入输出,实现属性内容的传输操作。虽然是Hashtable的子集,但是该类只能处理字符串
import java.util.*;
public class javaDemo{
public static void main(String[] args) {
Properties prop = new Properties();
prop.setProperty("one", "1");
prop.setProperty("two", "2");
System.out.println(prop.getProperty("one"));
System.out.println(prop.getProperty("THREE", "not found")); // 不存在这个key,返回not found
}
}
import java.io.File;
import java.io.FileOutputStream;
import java.util.*;
public class javaDemo{
public static void main(String[] args) throws Exception{
Properties prop = new Properties();
prop.setProperty("one", "1");
prop.setProperty("two", "2");
prop.store(new FileOutputStream(new File("info.properties")), "Very Import URL");
}
}
import java.io.File;
import java.io.FileInputStream;
import java.util.*;
public class javaDemo{
public static void main(String[] args) throws Exception{
Properties prop = new Properties();
prop.setProperty("one", "1");
prop.setProperty("two", "2");
prop.load(new FileInputStream(new File("info.properties"))); // 读取输入流的属性内容
System.out.println(prop.getProperty("one"));
}
}
可以使用Properties类读取属性文件将属性内容加载到程序中进行属性查询操作
七、Collections工具类
1. Collections
一些Collection未提供的方法在Collections类中提供
import java.util.*;
public class javaDemo{
public static void main(String[] args){
List<String> all = new ArrayList<>();
Collections.addAll(all, "Hello", "Helen","Hey!");
Collections.reverse(all);
System.out.println(Collections.binarySearch(all, "Helen"));
}
}
import java.util.*;
import java.util.stream.Stream;
public class javaDemo{
public static void main(String[] args){
List<String> all = new ArrayList<>();
Collections.addAll(all, "Hello", "Helen","Hey!");
Stream<String> stream = all.stream();
System.out.println(stream.filter((ele)-> ele.toLowerCase().contains("h")).count());
}
}
2. MapReduce
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
class Order { // 订单信息
private String name; // 商品名称
private double price; // 商品单价
private int amount; // 商品数量
public Order(String name, double price, int amount) {
this.name = name;
this.price = price;
this.amount = amount;
}
// setter方法、无参构造略 ...
public int getAmount() {
return amount;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
public class javaDemo{
public static void main(String[] args) throws Exception{
// 如果要想使用Stream进行分析处理,则一定要将全部要分析的数据保存在集合之中
List<Order> all = new ArrayList<Order>(); // List集合
all.add(new Order("狗熊娃娃", 9.9, 10)); // 数据添加
all.add(new Order("MLDN-极限IT", 2980.0, 3)); // 数据添加
all.add(new Order("MLDN系列教材", 8987.9, 8)); // 数据添加
all.add(new Order("MLDN定制笔记本", 2.9, 800)); // 数据添加
all.add(new Order("MLDN定制鼠标垫", 0.9, 138)); // 数据添加
DoubleSummaryStatistics stat = all.stream().filter((ele)-> ele.getName().toLowerCase().contains("mldn")).mapToDouble((order) ->
order.getAmount()*order.getPrice()).summaryStatistics();
System.out.println(stat.getMax());
System.out.println(stat.getSum());
}
}