java容器(集合)使用

1 篇文章 0 订阅
1 篇文章 0 订阅
版权声明:本文为博主原创文章,未经博主允许不得转载。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
注意中间没有空格

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值