Java进阶(异常,泛型,集合)

Java进阶(异常,泛型,集合)

异常

异常Throwable分为Error和Exception

  • Error :代表系统级别错误,属于严重问题,不是开发人员的问题。
  • Exception分为:
    • RuntimeException:运行时异常,以后的开发中可以尽量使用。
    • 其他异常:编译时异常,在编译阶段就会出现的异常。
  1. 自定义异常:可以自定义一个异常类来继承Exception,主方法中可以new这个异常类来抛出异常。

泛型

  • 作用:提供在 编译阶段 约束所能操作的数据类型,并自动进行检查,这样可以避免强制类型转换,及其可能出现的异常。

  • 把具体的数据类型作为参数传给类型变量。

  • 泛型类

    • 格式:修饰符 class 类名<类型变量,类型变量.......>{ },变量类型一般用大写的英文字母,常用的有:E,T,K,V。
  • 泛型接口

    • 修饰符 interface 接口名<类型变量,类型变量.......>{ },,变量类型一般用大写的英文字母,常用的有:E,T,K,V。

    • 例:

      //定义一个自定义泛型接口
      
      //这样就可以接收多种类型的对象,这些对象再调用这个add方法
      pubic interface Data<T> {
          void add(T date);
         	T query(int id);//根据id来查询对象信息,返回值为第一个对象 
      }
      
  • 泛型方法,通配符,上下限

    • 修饰符 <类型变量,类型变量.......> 返回值类型 方法名( ){ }
    • 通配符:就是“”,可以在使用泛型的时候代表一切类型,E,T,K,V,是在定义泛型的时候使用public static void go(ArrayList<?> cars){ }
    • 上下限(在使用泛型的时候,用通配符表示一切类型,但又要限制在某些类里面的时候):例:
      • 泛型上限:?extend Car:?表示能接收的必须是Car或者其子类。
      • 泛型下限:? super Car:?表示能接收的必须是Car或者其父类。
  • 泛型支持的类型

    • 泛型不支持基本数据类型,只能支持对象类型(引用数据类型)

    • 泛型擦除:泛型工作在编译阶段,等编译后泛型就没用了,所以泛型在编译后都会被擦除,所有类型会恢复成object类型。

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

      • int-->Integer char-->character 其他基本类型包装都是首字母大写。(double-->Double)
    • 如何包装?

      • Integer it=new Integer(100);//过时
      • Integer it=Integer.valueOf(100);//把100包装成一个整型对象。推荐这个方法,因为源代码中这个方法自动缓存了-128~127的整型数据对象,使读取速度更快。
    • 自动装箱:基本数据类型的数据可以直接变成包装对象的数据,不需要额外做任何事情

      • Integer it=100;//直接变成整型对象类型
    • 自动拆箱:把包装类型的对象直接给基本类型的数据

      • int i=it(it为对象类型)
    • 包装类新增的功能

      • 把基本类型数据转换成字符串

        int x=22;
        String str=Integer.toString(x);//str="22"
        //或者
        String str=x+"";//在两个类型相加时,有一方是String类型,那么整体为String类型,在这里相当于"22"+""。
        System.out.println(str+1);//"221"
        
      • 把字符串数值转换成对应的基本数据类型

        String str="100";
        int i=Integer.parseInt(str);
        //或者
        int i=Integer.valueOf(str);//推荐使用
        System.out.println(i+100);//200
        

集合

  • 集合是一种容器,用来装数据的,类似于数组,但集合的大小可变
  • 每个元素包含一个值

1. Collection单列集合:

  • 代表接口,包含List,Set

  • List接口系列集合:添加的元素是有序的,可重复的,有索引。

    • 实现类ArrayList、LinkedList:有序的,可重复的,有索引
  • Set接口系列集合:添加的元素是无序的,不重复,无索引。

    • 实现类HashSet:无序的,不重复,无索引
    • 实现类LinkedHashSet:有序的,不重复,无索引
    • 实现类TreeSet:按照大小默认升序排序,不重复,无索引
  • 把集合转换成数组:object[] arr = list.toArray();

  • Collection遍历

    • 迭代器遍历:

      Collection<String> names = new ArrayList<>();
      //存入数据后
      //得到这个集合的迭代器对象
      Iterator<String> it=names.iterator();
      System.out.println(it.next());//输出第一个元素
      System.out.println(it.next());//输出第二个元素。。。以此类推
      
      //使用一个while循环来遍历
      while(it.hasNext()){//判断该位置是否有值
          String name=it.next();
          System.out.println(name);
      }
      
    • 增强for循环

    • Lambda表达式

      集合名.forEach(new Consumer<String>(){
       	@Override
          public void accept(String s){
              System.out.println(s);
          }
       });
      
      //最终形式为:
      集合名.forEach(System.out::println);
      //常用形式:
      集合名.forEach(s->System.out.println(s));
      
  • 三种遍历方式的区别

    • 在遍历集合的同时进行修改集合时:
      • 如果集合支持索引,那么用for循环遍历,每删除数据后做i--;或者可以倒着遍历。
      • 也可以使用迭代器遍历,并用迭代器提供的删除方法删除数据
      • 增强for循环/Lambda遍历均不能解决并发修改异常问题,因此它们只适合做数据的遍历,不适合同时做增删操作。
  • List(接口)集合:

    • 两个常用的实现类:ArrayList(查询多)、LinkedList(增删多)
    • 它们底层采用的数据结构(存储和组织方式)不同。
      • ArrayList底层基于数组存储的,数组:根据索引查询数据更快,但是增删数据效率低。 (第一次加数据的时候进行扩容,默认长度为10,超过了就扩充为1.5倍的length大小)
      • LinkedList底层基于链表存储的,基于双链表实现,链表:查询数据慢,无论查询哪个数据都要从头开始找,增删相对数组来说更快

小案例

//设计一个电影信息管理系统

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class MovieService {
    //准备集合容器
    public static List<Movie> movies = new ArrayList<>();
    private static Scanner sc = new Scanner(System.in);

    public void start() {
        while (true) {
            // 准备cmd操作界面
            System.out.println("\t电影信息操作系统\t");
            System.out.println("1.上架某个电影");
            System.out.println("2.下架某个电影");
            System.out.println("3.查询某个电影");
            System.out.println("4.封杀某个明星的电影");
            System.out.println("5.退出");
            System.out.println("6.展示全部电影信息");
            System.out.println("请输入您要进行的操作:");

            int command = sc.nextInt();
            switch (command) {
                case 1:
                    System.out.println("请输入您要上架的电影");
                    addMovie();
                    break;
                case 2:
                    System.out.println("请输入您要下架的电影");
                    removeMovie();
                    break;
                case 3:
                    System.out.println("请输入您要查询的电影");
                    queryMovie();
                    break;
                case 4:
                    System.out.println("请输入您要封杀的电影");
                    deleteStar();
                    break;
                case 5:
                    System.out.println("成功退出!");
                    return;
                case 6:
                    System.out.println("展示全部电影信息:");
                    queryAllMovie();
                    break;
                default:
                    System.out.println("命令错误!");
                    break;
            }
        }
    }
    //展示全部电影
    private void queryAllMovie() {
        for (Movie movie : movies) {
            System.out.println(movie.getName()+" "+movie.getScore()+" "+movie.getActor()+" "+movie.getPrice());
        }
    }

    //封杀某个明星,下架其所有电影
    private void deleteStar() {
        System.out.println("请输入你要封杀的明星名称:");
        String star = sc.next();

        for (int i = 0; i < movies.size(); i++) {
            Movie movie = movies.get(i);
            if (movie.getActor().contains(star)) {
                movies.remove(movie);
                i--;
            }
        }
        queryAllMovie();
    }

    //下架功能
    private void removeMovie() {
        System.out.println("请输入你要下架的电影名称:");
        String name = sc.next();
        Movie movie = queryMovieByName(name);
        if (movie != null) {
            movies.remove(movie);
            System.out.println("下架成功!");
        } else System.out.println("没有找到这个电影!");
    }


    //上架功能
    private void addMovie() {
        //1.创建电影对象,封装这部电影信息
        Movie movie = new Movie();
        //2.给电影对象写入电影信息
        System.out.println("请输入电影名称");
        movie.setName(sc.next());
        System.out.println("请输入电影评分");
        movie.setScore(sc.nextDouble());
        System.out.println("请输入电影主演");
        movie.setActor(sc.next());
        System.out.println("请输入电影价格");
        movie.setPrice(sc.nextDouble());
        //3.将电影对象添加到集合中去
        movies.add(movie);
        System.out.println("上架成功!");

    }

    //查询功能
    private void queryMovie() {
        System.out.println("请输入你要查询的电影名称");
        String name = sc.next();
        Movie movie = queryMovieByName(name);
        if (movie != null) {
            System.out.println("查询成功!");
            System.out.println(movie.getName()+" "+movie.getScore()+" "+movie.getActor()+" "+movie.getPrice());
        } else System.out.println("没有找到这个电影!");
    }

    //按照名称查询功能
    private Movie queryMovieByName(String name) {
        for (Movie m : movies) {
            if (m.getName().equals(name)) {
                return m;//找到了
            }
        }
        return null;//没有找到
    }

}
//电影类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Movie {
private String name;
private double score;
private String actor;
private double price;
}
//测试类
public class Test {
    public static void main(String[] args) {
        MovieService service = new MovieService();
        service.start();
    }
}
  • Set(接口)集合:

    • 实现类HashSet:无序的,不重复,无索引

      • 底层原理:
      • 哈希值:一个int类型的随机值,Java中每个对象都有一个哈希值。可用public int hashCode( );返回对象的哈希码值。不同对象哈希值大概率不相等,但有可能会相等(哈希碰撞)。
      • Set第一次加数据的时候在底层加一个默认长度为16的数组。超过1.2倍的length时,扩充为两倍大小。
      • 链表长度超过8,并且数组长度>=64时,自动将链表转成红黑树(二叉平衡排序树)(树的结点,左小右大,左右子树高度相差不超过1)。
    • Set集合在进行去重操作时,若类型为引用类型(例:Student类),要在类中重写hashCode()和equals()两种方法,否则去重可能有问题。

    • 实现类LinkedHashSet:有序的,不重复,无索引

    • 实现类TreeSet:按照大小默认升序排序,不重复,无索引

2. Map双列集合

  • 每个元素包含两个值(键值对

  • 常用的实现类

    • HashMap<K,V>:由键决定特点,无序,不重复,无索引。
    • LinkedHashMap<K,V>:由键决定特点,有序,不重复,无索引。
    • TreeMap<K,V>:由键决定特点,按大小默认升序排序,不重复,无索引。
  • 遍历Map:

    • 1.键找值

         //1.提起Map集合的全部键到一个Set集合中去
         Set<String> keys = map集合名.keySet();
         //2.遍历Set集合,得到每一个键
         for(String key:keys){
             //根据键去找值
             Integer value = map.get(key);
             System.out.println(key + "=" + value);
         }
      
    • 2.键值对

      //创建Map集合,并存入数据
      Map <String ,Integer>map = new HashMap<>();
              map.put("a",1);
              map.put("b",2);
              map.put("c",3);
      	//把Map集合转换成Set集合,里面的元素类型是键值对类型(Map.Entry<String,Ingeter>)
             Set<Map.Entry<String,Integer>> entry=map.entrySet();
      		//再遍历Set集合,分别把键和值取出来输出
              for(Map.Entry<String,Integer> m:entry){
                      String key=m.getKey();
                      Integer value=m.getValue();
                      System.out.println(key+"="+value);
              }
      
    • Lambda方式

      map.forEach((k,v)->System.out.println(k+"="+v));
      
Map小案例

屏幕截图 2025-11-29 144637

import java.util.*;

public class test {
    public static void main(String[] args) {
    start();
    }
    public static void start() {
        Scanner sc = new Scanner(System.in);
        //创建一个List集合来存储学生选择的景点
        List<String> list = new ArrayList<>();
        //用数组来设定景点的种类
        String[] area={"A","B","C","D"};
        Random random=new Random();
        for (int i = 1; i < 80; i++) {
            //随机生成[0-4)的整数
            int index=random.nextInt(4);
            //将随机产生的数字作为景点下标存入集合中,就是随机一个景点存入集合中
            list.add(area[index]);
        }
        //设置一个Map容器来统计学生选择的景区及其票数
        Map<String,Integer> map=new HashMap<>();
        //遍历list集合
        for (String s : list) {
            if (map.containsKey(s)) {//如果map集合中存在该景点就让景点的票数加1
                map.put(s, map.get(s) + 1);
            } else {//如果map集合中不存在该景点就存入该景点作为键并且初始票数为1
                map.put(s, 1);
            }
        }
        //遍历map集合打印所有景点及其票数
        map.forEach((k,v)->{System.out.println(k+":"+v);});
    }
}
posted @ 2025-11-29 21:12  芒果学代码  阅读(2)  评论(0)    收藏  举报