版权声明:本文为博主原创文章,未经博主允许不得转载。https://blog.csdn.net/qq_44061725/article/details/98660888
本文为博主自身总结,仅供参考.如有错误,欢迎各位指正,谢谢
容器
List有序是通过下标索引来操作的,所以能分清每个元素,因此可以重复(有序可重复)
注意:List是有序,可重复的容器
__有序:__List中每个元素都有索引标记.可以根据元素的索引标记(在List中的位置)访问元素,从而精确控制这些元素
__可重复:__List允许加入重复的元素.更确切地讲,List通常允许满足e1.equals(e2)的元素重复加入容器.(而set是equals()返回true不加入容器)
顶级接口java.util.Collection(存放的是元素本身)和java.util.Map(存放的是键值对)
Collection接口下面有两个常用的子接口,分别是List(有序,可重复)和Set(无序,不可重复),Set接口下面有一个常用的子接口,SortedSet(有序的,不可重复)
List接口的常用实现类:ArrayList,LinkedList
Set接口的常用实现类:HashSet,TreeSet
Map接口下面最常用的实现类是:HashMap,
Map接口的子接口SortedMap,实现类是TreeMap
List
ArrayList实现类
//ArrayList是有序,可重复的集合,它的底层实现是数组,所以查询效率高,增删效率低!
// 一.集合的创建
// 1.JDK5.0之前,没有泛型[不推荐]
// 注意:泛型使用来约束集合数据类型的
// ArrayList list = new ArrayList();
// 2.JDK5.0之后,加入泛型,统一某个集合存放数据类型必须相同
// ArrayList<String> list = new ArrayList<String>();
// 3.JDK7.0之后,简化创建
// 创建一个默认容量为10的字符串空容器
ArrayList<String> list = new ArrayList<>();
// 第三方工具Jar包创建集合对象,并且直接赋值
// a.Google Guava
ArrayList<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6);
// b.Apache Commons Collections » 4.4
// c.JDK9.0加入的集合工具类
// 注意:此方式创建的集合是不可变的集合,如果对集合进行CRUD,则抛出异常
List<String> strList = List.of("jack", "rose", "Lilei");
System.out.println(strList);
// 二. 常用方法
// 1.添加元素
list.add("AA");
list.add("CC");
list.add("DD");
list.add("DD");
list.add(1, "BB");// 指定下标追加
// 2.清空集合元素
// list.clear();
// 3.判断集合是否包含指定元素
System.out.println(list.contains("AA"));
// 4.判断集合中指定元素第一次/最后一次出现的下标,如果不存在,则返回-1
System.out.println(list.indexOf("DD"));
System.out.println(list.lastIndexOf("DD"));
// 5.判断集合是否为空
System.out.println(list.isEmpty());
// 6.集合元素删除
list.remove(0);// 根据下标删除元素
list.remove("DD");// 根据对象删除[只删除第一个匹配的对象]
//注意:是remove而不是delete.只是从容器中移出去,而此对象实际还在
//即:容器存放的也是数据的引用地址
//因为上边的intList集合是Integer泛型,而remove()重载了根据下标删除和根据对象删
//除元素,因此参数传递数字时,默认为根据下标,可以用下边方式根据对象删除
// intList.remove(Integer.valueOf(1));//根据对象删除
// System.out.println(intList);
// 7.修改集合指定元素
list.set(2, "EE");
// 8.集合截取
System.out.println(intList);
List<Integer> subList = intList.subList(2, 4); //[2,4)
System.out.println(subList);
/* 集合和数组的互转 */
// 数组-->集合
// List<Integer> integers = Arrays.asList(new Integer[]{ 1, 2, 3 });
// List<Integer> integers = Arrays.asList(1, 2, 3);
// 集合-->数组
// 空参方法返回的Object[]类型的数组,所以涉及到类型转换,存在风险!
// Object[] arr1 = intList.toArray();
// 传参版本推荐使用,数据类型确定安全
Integer[] newArr = intList.toArray(new Integer[] {});
System.out.println(Arrays.toString(newArr));
int[][] arr = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.deepToString(arr));
System.out.println("--------------------------");
// 三. 输出集合
// 0.JDK8.0+,lambda表达式
// list.forEach(str -> System.out.println(str));
list.forEach(System.out::println);
// 1.直接打印
System.out.println(list);
// 2.for循环
// size()用来获取集合元素个数
for (int i = 0; i < list.size(); i++) {
// get(index),通过下标获取集合元素
System.out.println(list.get(i));
}
// 3.增强for循环[可以迭代无序集合]
for (String s : list) {
System.out.println(s);
}
// 4.迭代器[可以迭代无序集合]
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
System.out.println("--------------------------");
List<String> list2 = Lists.newArrayList("BB", "CC", "DD");
list.removeAll(list2);// 移除list中所有list2中也有的元素(移除交集元素)
System.out.println(list); // [EE]
System.out.println("--------------------------");
list.addAll(list2); // 把list2中所有元素加入到list中(包括重复的)
System.out.println(list);
System.out.println(list2);
System.out.println("--------------------------");
list.retainAll(list2); // 操作list,保留list和list2中都有的元素(保留交集元素)
System.out.println(list);
System.out.println(list2);
List集合排序
Student s1 = new Student("candy", 25);
Student s2 = new Student("ann", 25);
Student s3 = new Student("aben", 23);
List<Student> students = Lists.newArrayList(s1, s2, s3);
// JDK8.0 Stream API
/*
* 注意:sorted()方法排序对象时,必须指定排序规则,否则抛出类型转换异常:java.lang.ClassCastException
* 排序规则指定方式:
* 一.让被排序的实体类实现java.lang.Comparable接口,并且重写接口中的抽象方法compareTo(obj)方法(不推荐使用)
* 二.写一个类[匿名内部类]实现java.util.Comparator接口,并且重写其中的compare(o1,o2)方法(推荐)
*/
/*Comparator<Student> c = new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getAge() - o1.getAge();
}
};*/
// 创建单个排序规则
// Comparator<Student> c = (o1, o2) -> o1.getAge() - o2.getAge();
// 使用工厂类类实现多重排序规则
Comparator<Student> c =ArraySortedFactory.getComparator(AGE_MAX_TO_MIN);
students.stream().sorted(c).collect(Collectors.toList()).forEach(System.out::println);
System.out.println("---------------------------------------");
// JDK8.0之前,用java.util.Collections工具类,它提供了List集合的相关操作方法
// Collections.sort(students); //Student实体类要实现Comparable接口
Collections.sort(students, c);
students.forEach(System.out::println);
System.out.println("倒序元素:");
Collections.reverse(students);
students.forEach(System.out::println);
// 随机打乱集合元素
System.out.println("随机打乱:");
Collections.shuffle(students);
students.forEach(System.out::println);
类Student:
class Student /*implements Comparable<Student>*/ {
private String name;
private int age;
// 按照年龄降序排列,如果年龄相同,则按照姓名升序排列
int i = age - o.getAge();
if (i == 0) {
returnname.compareTo(o.getName());
}
return o.getAge() - age;
}
/**集合排序工厂*/
public class ArraySortedFactory {
public static final int AGE_MAX_TO_MIN = 1;
public static final int AGE_MIN_TO_MAX = 2;
public static final int NAME_MAX_TO_MIN = 3;
public static final int NAME_MIN_TO_MAX = 4;
public static final int AGE_NAME_MAX_TO_MIN = 5;
public static Comparator<Student> getComparator(int type) {
Comparator<Student> comparator = null;
if (type == AGE_MAX_TO_MIN) {
comparator = (o1, o2) -> o2.getAge() - o1.getAge();
} else if (type == AGE_MIN_TO_MAX) {
comparator = (o1, o2) -> o1.getAge() - o2.getAge();
} else if (type == NAME_MAX_TO_MIN) {
comparator = (o1, o2) ->o2.getName().compareTo(o1.getName());
} else if (type == NAME_MIN_TO_MAX) {
comparator = (o1, o2) -> o1.getName().compareTo(o2.getName());
} else if (type == AGE_NAME_MAX_TO_MIN) {
comparator = (o1, o2) -> {
int i = o1.getAge() - o2.getAge();
if (i == 0) {
return o1.getName().compareTo(o2.getName());
}
return o2.getAge() - o1.getAge();
};
} else {
throw new IllegalArgumentException("参数不合法...");
}
return comparator;
}
}
Java集合元素删除
public class ArrayListRemoveDemo {
public static void main(String[] args) {
List<Integer> list = Lists.newArrayList(1, 2, 3, 3, 3, 1, 8);
deleteElement(list, 3);
list.forEach(System.out::println);
}
// 删除集合中指定的元素
public static void deleteElement(List<Integer> list, int target) {
/*
* 错误1:此方式删除集合元素有BUG,当要被删除的两个元素相邻时,第二个元素失败
* 原因:删除元素后,后面的元素将向前移动,此时下标继续往后移动
* 所以会岔开一个位置,无法检测被删除的第一个元素紧接着的元素
* 解决: a.删除后,i不自增 b.反向删除
*/
/*for (int i = 0; i < list.size(); i++) {
if (list.get(i) == target) {
list.remove(i);
}
}*/
// 反向删除避免BUG
/*for (int i = list.size() - 1; i >= 0; i--) {
if (list.get(i) == target) {
list.remove(i);
}
}*/
/*
* 错误2:用集合迭代器在迭代过程中进行删除,将抛出并发修改异常:
* java.util.ConcurrentModificationException
* 原因:集合迭代器不支持并发操作 修改:调用迭代器自身的删除方法即可
*/
Iterator<Integer> iter = list.iterator();
while (iter.hasNext()) {
Integer i = iter.next();
if (i == target) {
// list.remove(Integer.valueOf(i));
// 调用迭代器自身的删除方法
iter.remove();
}
}
}
}
LinkedList
public class LinkedListDemo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请你输入括号字符串:");
String str = scanner.nextLine();
System.out.println(check(str));
scanner.close();
}
/**
* 进行括号匹配
* OK: ()[] []{} [{}] {()[]} ...
* ERROR: ([)] {([)]} ...
*/
public static boolean check(String str) {
// 创建一个LinkedList/Stack来模拟栈
LinkedList<Character> list = new LinkedList<>();
// 获取输入的字符串的第一个字符
char first = str.charAt(0);
// 把第一个字符压入到栈顶
list.push(first);
// 从第二个字符开始循环输入的字符串
for (int i = 1; i < str.length(); i++) {
// 得到字符串中每一个字符,要判断是否要入栈的元素(除了第一个)
char c = str.charAt(i);
// 注意:判断,如果集合为空,则直接添加元素
if (list.isEmpty()) {
list.push(c);
} else {
// 获取栈顶元素,不删除
char top = list.peek();
// 把得到的字符和LinkedList集合中的第一个元素对比,如果能成
// 对,则删除栈顶元素,如果不能成对,则直接添加
if (top == '(' && c == ')' || top == '[' && c == ']' || top == '{' && c == '}') {
// 弹出栈顶元素(删除集合第一个元素)
// ?????????????????? get()根据索引得到的值顺序相反
System.out.println(list.get(0));
list.pop();
} else {
// 添加即可
list.push(c);
}
}
}
// 检查栈,如果栈为空,则说明全部匹配
if (list.isEmpty()) {
return true;
}
return false;
}
}
Set
HashSet实现类
Set接口下的实现类HashSet和Set接口下的子接口SortedSet的实现类TreeSet[有序不可重复]
Set集合的特点:
无序,不可重复
注意:此处的无序是指添加元素的顺序非最终元素存储的顺序
/*Set<String> set = new HashSet<>();
set.add("ben");
set.add("jack");
set.add("ben");
set.add("rose");*/
// JDK9.0提供创建固定不能修改的集合对象
// Set<String> set = Set.of("ben", "jack", "ben", "rose");
// Guava工具
Set<String> set = Sets.newHashSet("ben", "jack", "ben", "rose");
// 输出set集合
// 0. forEach
set.forEach(System.out::println);
// 1.直接打印
System.out.println(set);
// 2.增强for循环
for (String s : set) {
System.out.println(s);
}
// 3.迭代器
Iterator<String> iter = set.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
System.out.println("-------------------------------------------");
HashSet是如何实现无序不可重复的?
- 当第一个元素添加到Set集合中时,会自动调用该对象的hashCode()方法,得到散列码,根据这个 散列码来决定元素存放的位置.
- 当第二个元素添加到Set集合中时,同样会自动调用这个对象的hashCode()方法,得到散列码,如 果该散列码和前面对象不同,则根据这个散列码来安排这个对象存放的位置[位置不一定是在 之前元素之后];如果该散列码和前面对象相同,此时还不能说明这两个对象时同一个对象
- 然后继续调用对象的equals()方法,如果equals()方法true,说明是同一个对象,则该对象就 不再添加了
- 如果equals()方法返回false,说明这两个对象是不同对象,但是恰巧hashCode一样,则会根据 情况来自行存放对象
根据情况如下:
-
JDK8.0之前,处理方式是数组+链表
缺点:当同一个位置元素过多时(链表长度过大),会大大降低集合性能 -
JDK8.0之后,处理方式是数组+链表==>红黑树,当链表阔值超过8时,自动转换成红黑树(二叉树),它可以极大的提升检索性能,从而最终导致整个集合的性能提升.
测试如下:
//main方法中...
Employee e1 = new Employee("jack", 10000);
Employee e2 = new Employee("rose", 12000);
Employee e3 = new Employee("jack", 10000);
Set<Employee> employees = Sets.newHashSet(e1, e2, e3);
employees.forEach(System.out::println);
在该Employee类中重写了equals()和hashcode(),其中都进行了打印语句,方便观察
class Employee {
private String name;
private double salary;
//get,set,构造等省略
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 :name.hashCode());
long temp;
temp = Double.doubleToLongBits(salary);
result = prime * result + (int) (temp ^ (temp >>> 32));
System.out.println("--hashCode:" + result);
return result;
}
@Override
public boolean equals(Object obj) {
System.out.println("--equals()");
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
return false;
return true;
}
TreeSet
java.util.TreeSet集合,特点是有序,不可重复
有序则是必须给出排序规则
Employee e1 = new Employee("jack", 10000);
Employee e2 = new Employee("rose", 12000);
Employee e3 = new Employee("tom", 11000);
// 在TreeSet的构造方法中传入比较器对象来实现根据指定的规则排序
Comparator<Employee> c = (o1, o2) -> (int) (o2.getSalary() - o1.getSalary());
Set<Employee> set = new TreeSet<>(c);
set.add(e1);
set.add(e2);
set.add(e3);
set.forEach(System.out::println);
Map
Map集合的特点是双列集合,即集合中存放的不单单是元素本身,而是键值对(KEY-VALUE),
KEY无序不可重复,VALUE是可以重复的,相同key值后者会把前者覆盖!
HashMap
// 创建Map集合
// 注意:map的key类型一般是Integer或者String
// value的类型往往是一个对象或者集合(数组)
Map<Integer, String> map = new HashMap<>();
// 添加元素
map.put(1, "one");
map.put(2, "two");
map.put(3, "two");
map.put(1, "one-again");
// 结论:map是key无序不可重复的集合,value可以重复,相同key值后者会把前者覆盖!
// 常用方法
// 1.判断集合是否包含指定的key或者value
System.out.println(map.containsKey(2));
System.out.println(map.containsValue("two"));
// 2.根据key获取value
// 注意:不是通过下标获取,map是无序的,不存在下标!!!
System.out.println(map.get(3));
// 3.把Map中所有的value转换成Collection对象!!!!!!!!!!!!!!!!!values()
Collection<String> collection = map.values();
System.out.println(collection);
List<String> arrayList = new ArrayList<>(collection);
System.out.println(arrayList);
Set<String> set = new HashSet<>(collection);
System.out.println(set);
System.out.println("---------------------------");
// 打印map
// 1.直接打印
System.out.println(map);
// 2.keySet遍历
// a.把map中所有的key值放入到Set集合
Set<Integer> keys = map.keySet();
// b.遍历Set集合,即可获取map中所有的key
Iterator<Integer> iter = keys.iterator();
while (iter.hasNext()) {
Integer key = iter.next();
// c.根据key获取value
String value = map.get(key);
System.out.println(key + "-" + value);
}
// 3.entrySet遍历
// a.把map中所有的键值对封装成各个Entry对象,然后放入到Set集合中
Set<Entry<Integer, String>> entry = map.entrySet();
// b.遍历Set集合,得到每个键值对对象
Iterator<Entry<Integer, String>> iter2 = entry.iterator();
while (iter2.hasNext()) {
// Entry对象即键值对
Entry<Integer, String> e = iter2.next();
// 通过Entry对象获取键值
Integer key = e.getKey();
String value = e.getValue();
System.out.println(key + "-" + value);
}
System.out.println("------------------------------------");
// JDK9.0新创建方法
// 注意:创建的集合是不可变
Map<Integer,String> newMap = Map.of(2,"two",3,"three",4,"four",1,"one");
System.out.println(newMap);
System.out.println("------------------------------------");
List转为Map进行分类
Product2 p1 = new Product2("宝洁", "洗衣液", 5.5);
Product2 p2 = new Product2("多芬", "沐浴露", 5.5);
Product2 p3 = new Product2("多芬", "洗发露", 5.5);
Product2 p4 = new Product2("佳洁士", "牙膏", 5.5);
Product2 p5 = new Product2("宝洁", "洗手液", 5.5);
Product2 p6 = new Product2("多芬", "护发素", 5.5);
Product2 p7 = new Product2("霸王", "洗发露", 5.5);
Product2 p8 = new Product2("佳洁士", "牙刷", 5.5);
Product2 p9 = new Product2("宝洁", "香皂", 5.5);
Product2 p10 = new Product2("佳洁士", "漱口水", 5.5);
// 补充:可以通过DataFactory的工具类来自动模拟数据!
List<Product2> products=Lists.newArrayList(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10);
Map<String, List<Product2>> productMap = processData(products);
System.out.println(productMap);
// 统计宝洁商品数量
System.out.println("宝洁商品个数:" + productMap.get("宝洁").size());
Collection<List<Product2>> lists = productMap.values();
System.out.println(lists);
}
//把产品的List集合转换成按照品牌来分类的Map集合
public static Map<String,List<Product2>> processData(List<Product2> products) {
// 创建Map集合
Map<String, List<Product2>> productMap = new HashMap<>();
// 循环List集合
for (int i = 0; i < products.size(); i++) {
// 得到每个商品
Product2 product = products.get(i);
// 得到每个商品的品牌
String brand = product.getBrand();
// 把Product对象添加到Map集合中,由于Map集合相同KEY会覆盖,所以需要先
// 判断集合中是否包含指定的KEY
if (productMap.containsKey(brand)) {
// 说明Map集合中已经存在该品牌的商品了,则直接通过品牌获取对应的集合,然
// 后往集合中添加一个商品即可
productMap.get(brand).add(product);
} else {
// 说明Map中没有该品牌的商品,则直接添加
List<Product2> pList = new ArrayList<>();
pList.add(product);
productMap.put(brand, pList);
}
}
return productMap;
}
@Data
@AllArgsConstructor
class Product {
private String brand;
private String name;
private Double price;
}
LinkedHashMap(有序)
有序的Map -> java.util.LinkedHashMap
LinkedHashMap<Integer, String> map = new LinkedHashMap<>();
map.put(1, "one");
map.put(3, "three");
map.put(1, "one-again");
map.put(2, "two");
System.out.println(map);
Properties类
java.util.Properties的演示
HashMap和HashTable两个集合,前者是多线程并发不安全的,性能高
后者是多线程并发安全的,性能低
Properties是HashTable的子类,也就是说,Properties是线程安全的!
总结:
Properties是一个Key为String,value也是String的线程安全的Map集合
// 1.获取系统属性键值
// Properties properties = System.getProperties();
// System.out.println(properties);
// 输出系统属性键值列表
// properties.list(System.out);
// 单独获取某一个键值信息
// System.out.println(properties.getProperty("os.name"));
System.out.println("-------------------------------------------");
// 2.(极其重要),加载属性文件
Properties properties = null;
try {
// a.创建空属性集合对象
properties = new Properties();
// b.把本地properties属性文件转换成Java对象(后面要学习的IO流对象)
InputStream in = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("com/buendia/day0807/config.properties");
// c.属性集合对象加载配置文件
properties.load(in);
} catch (IOException e) {
e.printStackTrace();
}
Scanner scanner = new Scanner(System.in);
System.out.println("请你输入用户名:");
String username = scanner.nextLine();
System.out.println("请你输入密码:");
String password = scanner.nextLine();
if (username.equals(properties.getProperty("username"))
&& password.equals(properties.getProperty("password"))) {
System.out.println("登录成功...");
} else {
System.out.println("登录失败...");
}
scanner.close();
把本地properties属性文件转换成Java对象
新建一个文件config.properties,写入类似:
#注释
username=admin
password=123
注意中间没有空格