跳过正文
Java集合框架
  1. TP` Blog/

Java集合框架

·2 分钟· loading ·
龙城飞将
作者
龙城飞将
最美的是月亮🌙……
目录
Java学习之旅 - 这篇文章属于一个选集。
§ 6: 本文

1. 异常和泛型
#

1.1 异常
#

(1) 代码程序出现的问题

  • 文件不存在
  • 断网

(2) 异常体系

  • Error(系统级别的错误,如内存溢出,程序员解决不了)
  • Exception(异常)
    • RuntimeException(运行异常):编译时不会出错,如索引越界
    • 其他异常(编译时异常):写代码就有错误

(3) 处理方式

  • 抛出异常(throwthrows
  • 捕获异常(try … catch

(4) 作用

  • 定位程序BUG信息
  • 作为方法内部的一种特殊返回值,以便通知上层调用者

(5) 自定义异常(定义一个异常类继承Exception

  • 自定义运行异常
  • 自定义编译时异常

最好不要使用自定义异常,需要一层一层的上报异常很麻烦,可使用运行时异常

2.2 泛型
#

本质:把具体的数据类型参数类型作为参数传给类型变量

(1)定义类,接口,方法时同时声明一个或者多个类型变量<E>,称为泛型类,泛型接口,泛型方法

public class ArrayList<E>{}

(2) 作用

约束数据类型,避免强制类型转换

(3)自定义泛型类、接口、方法

<E, T, K, V>可以不止一个类型参数

// 泛型类
public class MyArrayList<E>{}

MyArrayList<E> myList = new MyArrayList<>();
//泛型接口
public interface Data<T>{
		void add(T t);
		T qurry(int id);
}

public class StudentData implements Data<Student>{}

//泛型方法
public static <T> void test(T t){}

(4)通配符

“?”,在使用泛型时代表一切类型

(5)上下限

限制通配符?

  • 泛型上限:?extends Car :接受的必须是Car或者子类
  • 泛型下限:?super Car: 必须是Car或者父类
public static  void test(ArrayList<? extends Car> cars){}
public static  void test(ArrayList<? super Car> cars){}

(6)泛型支持的类型

  • 不支持基本数据类型

  • 只支持对象类型(引用类型)

  • 包装类:基本的数据类型包装成对象类型

    • byte Byte
    • short Short
    • int Integer(不同)
    • long Long
    • char Character(不同)
    • float Float
    • double Double
    • boolean Boolean

    注:Integer.valueOf()封装了(-128~127)对象

    Integer it1 = 100; Integer it2 = 100;是指向同一个对象

    Integer it1 = 130; Integer it2 = 130;不是指向同一个对象,已经越界

    自动包装和去拆包装,集合存的是对象,取出来可以自动变成一般数据类型

(7)包装类的其他功能(要记住)

  • 把基本数据类型变成字符串:Integer.toString()

  • 把字符串类型数值转成基本数据类型(重点)

    String str = "99";
    int i = Integer.parseInt(str);
    int i2 = Integer.valueOf(str);//也行
    

2. 集合框架
#


  • Collection:单列集合(单个值)
  • Map:双列集合(键值对)

2.1 Collection:祖先接口,下面是实现类
#

  • List:数据有序,可重复,有索引

    • ArrayList: 数组(根据索引查询数据速度快,所有数据查询时间相同,增删数据效率低)

      注意: 在添加数据时,会在第一次添加数据时扩容grow()10个容量 ,加满后再次扩容到原来的1.5倍

    • LinkedList:链表(查询数据慢,增删效率高)(节点组成,每个节点包含元素和下一个节点的地址)

      注意:LinkedList是基于双链表实现的,包含了下一节点和上一节点地址,可以从前往后或者从后往前查询,有很多对首尾节点的操作方法(增删取)

  • Set:数据无序,不重复,无索引

    • HashSet

      哈希值:Java对象调用hashCode()返回哈希值,同以个对象多次调用是相同的,不同对象有小概率相同(哈希碰撞)

      无序的底层原理:基于哈希表存储(jdk8之前数组+链表,大小默认16加载因子0.75;之后是数组+链表+红黑树),计算后的哈希地址大小导致数据无序存储,出现同一位置会将新数据用链表挂在老元素下面(jdk8之前反过来)

      扩容:元素的数量超过大小*加载因子就会扩容到之前2倍

      注意:JDK8开始,当链表长度超过8,且数组长度≥64,自动转换成红黑树(提升检索效率)

      • LinkedHashSet:(有序)
    • TreeSet:(按照大小默认升序)

    HashSet集合元素去重操作(经典操作)

    //创建多个学生对象,若学生对象中的的成员变量相同则就是同一个对象
    Student s1 = new Student("张三",19);
    Student s2 = new Student("张三",19);
    //重写hashCode()和equals()
    //计算哈希地址一样,再计算两个对象的内容一致,(不同的对象哈希地址有一点的概率相同)
    

(1)Collection遍历方式

  • 迭代器遍历:遍历集合的专用方式(数组没有)

    Iterator<E> it = names.iterator();//返回集合中的迭代对象
    String name = it.next();//取出元素,并移位
    // it.hashNext() 判断当前位置是否有数据
    
  • 增强for循环

    for (元素的数据类型 变量名  数组或者集合){
    }
    
    Collection<String> c = new ArrayList<>();
    for (String s : c ){
    }
    
  • Lambda 表达式:forEach()

    Collection<String> c = new ArrayList<>();
    
    c.forEach(new Consumer<String>() {
    		@Override
    		public void accept(String s){
    				//输出
    				System.out.println(s);
    		}
    });
    
    //简化
    c.forEach(s -> System.out.println(s));
    

(2)Collection3个遍历方式的区别

场景:认识并发修改异常问题:遍历集合同时存在集合的增删元素出现业务异常

  • (有索引)for 循环在删除数据时进行一次减一(i--)操作或者倒序遍历
  • 迭代器遍历:(没有索引)使用迭代器自带的remove()方法可以避免这个问题(索引会自动同步)
  • 增强for循环和Lambda 表达式都没办法解决(集合自己删除,不会控制索引)

在遍历并删除时,有索引的集合可以根据for循环操作,没有索引的集合只能使用迭代器遍历使用迭代器的方法

2.2 Map<K,V>:祖先接口
#

map集合:键值对,格式{key1=value1,key2=value2,…}

键不能重复,值可以重复,键值一一对应

  • HashMap<K,V>:(由键决定)无序,不重复,无索引

    底层原理与HashSet()一样,基于哈希表实现,HashSet()是调用HashMap()实现

    • LinkedHashMap<K,V>:有序,不重复,无索引

      LinkedHashSet()的底层原理就是LinkedHashMap()

  • TreeMap<K,V>:升序,不重复,无索引

Map<String, Integer> map = new HashMap<>();
map.put("张三", 12);
map.put("李三", 12);
map.get("张三");//根据键取值
map.cantainsKey("张三");//返回true
map.cantainsValue("12");//返回true
map.remove("张三");//删除键值对,返回值
map.isEmpty();//判断是否为空
map.size();//返回键值对个数

//重要,**获取所有键,返回一个Set键集合**
Set<String> keys = map.keySet();
//重要,**获取所有value,返回一个Collection键集合**
Collection<Integer> values = map.values();

(1)Map遍历方式

  • 键找值(for 循环)

    Map<String, Integer> map = new HashMap<>();
    map.put("张三", 12);
    map.put("李三", 12);
    Set<String> keys = map.keySet();
    for (String key :keys){
    		Integer value = map.get(key);
    		//输出
    }
    
  • 键值对整体遍历(Entry对象封装整个键值对)

    Set <Map.Entry<StringDouble>> entries = map.entrySet();
    for (Map.Entry<StringDouble> entry:entries ){
    		String key = entry.getKey();
    		double value = entry.getValue();
    		//输出
    }
    
  • Lambda表达式(forEach方法)

    Map<String, Integer> map = new HashMap<>();
    map.put("张三", 12);
    map.put("李三", 12);
    
    //简化
    map.forEach((k, v) -> System.out.println(k + v));
    
Java学习之旅 - 这篇文章属于一个选集。
§ 6: 本文