异常、泛型、集合框架

news2024/11/29 7:29:05

一、异常

1、认识异常

异常代表程序出现的问题。

Java的异常体系:Java.lang.Throwable之下的异常类。

Throwable(父类)-->Error/(Exception-->RuntimeException/其他异常)

Error:系统级别错误(属于严重问题),系统一旦出现问题,sun公司会把这些问题封装成Error对象给出来,如:内存溢出、栈溢出等。

Exception:异常,代表程序可能出现的问题,程序员通常会用Exception以及它的孩子来封装程序出现的问题。分为运行时异常和编译时异常

  • 运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,程序运行过程中出现的问题,如:空指针异常、数组索引越界异常等。
  • 编译时异常:编译阶段出现错误提醒的问题,如:语法错误、类型转换错误等。

异常的基本处理:

  • 抛出异常(throws):在方法上使用throw关键字,可以将方法内部出现的异常抛出去给调用者处理。方法() throws 异常1,异常2{ }//或遇到两个异常只抛出父异常Exception。
  • 捕获异常(try...catch):直接捕获程序出现的异常。try{ } catch(异常类型1 变量){ } catch(异常类型2 变量){ }

异常的作用:

  • 异常是用来定位程序bug的关键信息。
  • 可以作为方法内部的一种特殊返回值,以便通知上层调用者,方法的执行问题。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ExceptionDemo1 {
    public static void main(String[] args){
        //认识异常的体系,搞清楚异常的基本作用
        //show();
        try {
            //监视代码,出现异常,会被catch拦截住这个异常
            show1();
        } catch (Exception e) {
            e.printStackTrace();//打印异常信息
        }
    }

    //定义一个方法认识编译时异常
    public static void show1() throws Exception{
        System.out.println("show1方法执行了...");
        //编译异常:编译阶段报错,编译不通过
        String str="2024-07-09 11:12:13";
        //把字符串时间解析成Java的一个日期对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse(str);//编译时异常,提醒程序员这里的程序很容易出错,请注意
        System.out.println(date);

        InputStream is=new FileInputStream("D:/meinv.png");

        System.out.println("show1方法结束了");
    }

    //定义一个方法认识运行时异常
    public static void show(){
        System.out.println("show方法执行了...");
        //运行时异常特点:编译阶段不报错,运行时出现的异常,继承自RuntimeException
        int[] arr = {10,20,30};
        //int res = arr[3];
        //System.out.println(res);//输出:运行时异常,数组越界异常,ArrayIndexOutOfBoundsException

        //System.out.println(10/0);//输出:运行时异常,除数不能为0,ArithmeticException

        //空指针异常
        String str = null;
        System.out.println(str.length());//输出:运行时异常,空指针异常,NullPointerException

        System.out.println("show方法结束了");
    }
}
public class ExceptionDemo2 {
    public static void main(String[] args) {
        //搞清楚异常的作用
        System.out.println("程序开始执行");
        try {
            System.out.println(div(10,0));
            System.out.println("底层方法执行成功了");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("底层方法执行失败了");
        }
        System.out.println("程序结束");
    }

    //求两个数的除的结果,并返回这个结果
    public static int div(int a,int b) throws Exception {
        if(b==0){
            System.out.println("除数不能为0");
            //可以返回一个异常给上层调用者,返回的异常还能告知上层底层是执行成功了还是执行失败了
            throw new Exception("除数不能为0");
        }
        int result=a/b;
        return result;
    }
}

2、自定义异常

Java无法为这个世界上全部的问题都提供异常类来代表,如果企业自己的某种问题想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类。

1、自定义编译时异常:定义一个异常类继承Exception类,并重写构造方法,通过throw new 异常类(xxx) 创建异常对象并抛出。

2、自定义运行时异常:定义一个异常类继承RuntimeException类,并重写构造方法,通过throw new 异常类(xxx) 创建异常对象并抛出。

//自定义编译时异常
//1、继承Exception做爸爸
//2、重写Exception的构造器
//3、哪里需要用这个异常返回,哪里就throw这个异常
public class AgeIllegalException extends Exception{
    public AgeIllegalException(){

    }
    public AgeIllegalException(String message){
        super(message);
    }
}

public class ExceptionDemo3 {
    public static void main(String[] args) {
        //认识自定义异常
        System.out.println("程序开始执行");
        try {
            saveAge(300);
            System.out.println("年龄保存成功");
        } catch (AgeIllegalException e) {
            e.printStackTrace();
            System.out.println("年龄非法,保存失败");
        }
        System.out.println("程序结束");
    }

    //需求:我们公司的系统只要收到了年龄小于1岁或者大于200岁就是一个年龄非法异常
    public static void saveAge(int age) throws AgeIllegalException {
        if(age<1||age>200){
            //年龄非法,抛出去一个异常返回
            throw new AgeIllegalException("年龄非法 age 不能低于1岁不能高于200岁");
        }else{
            System.out.println("年龄合法");
            System.out.println("保存年龄"+age);
        }
    }
}
//自定义运行时时异常
//1、继承RuntimeException做爸爸
//2、重写RuntimeException的构造器
//3、哪里需要用这个异常返回,哪里就throw这个异常
public class AgeIllegalRuntimeException extends RuntimeException{
    public AgeIllegalRuntimeException(){

    }
    public AgeIllegalRuntimeException(String message){
        super(message);
    }
}

public class ExceptionDemo4 {
    public static void main(String[] args) {
        //认识自定义异常-运行时异常
        System.out.println("程序开始执行");
        try {
            saveAge(300);
            System.out.println("年龄保存成功");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("年龄非法,保存失败");
        }
        System.out.println("程序结束");
    }

    //需求:我们公司的系统只要收到了年龄小于1岁或者大于200岁就是一个年龄非法异常
    public static void saveAge(int age){
        if(age<1||age>200){
            //年龄非法,抛出去一个异常返回
            throw new AgeIllegalRuntimeException("年龄非法 age 不能低于1岁不能高于200岁");
        }else{
            System.out.println("年龄合法");
            System.out.println("保存年龄"+age);
        }
    }
}

如果想要表达强烈的提醒(他人易犯的错误),就用编译时异常(少用),若程序员自己能避免(别人不易犯错),就使用运行时异常(多用)

3、异常的处理方案

1、底层异常层层往上抛出,最外层捕获异常,记录下异常信息,并响应适合用户观看的信息进行提升。

2、最外层获取异常后,尝试重新修复。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ExceptionDemo5 {
    public static void main(String[] args) {
        //掌握异常的处理方案1:底层异常都抛出去给最外层调用者,最外层捕获异常,记录异常,响应合适信息给用户观看
        System.out.println("程序开始执行");
        try {
            show();
            System.out.println("这次操作成功了");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("这次操作失败了");
        }
        System.out.println("程序结束");
    }

    public static void show() throws Exception {

        //编译异常:编译阶段报错,编译不通过
        String str="2024-07-09 11:12:13";
        //把字符串时间解析成Java的一个日期对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse(str);//编译时异常,提醒程序员这里的程序很容易出错,请注意
        System.out.println(date);

        InputStream is=new FileInputStream("D:/meinv.png");

    }
}
import java.util.Scanner;

public class ExceptionDemo6 {
    public static void main(String[] args) {
        //掌握异常的处理方案2:捕获异常对象,尝试重新修复
        //接收用户的一个定价
        System.out.println("程序开始执行");
        while (true) {
            try {
                double price  = userInputPrice();
                System.out.println("用户成功设置了商品定价"+price);
                break;
            } catch (Exception e) {
                //e.printStackTrace();
                System.out.println("用户输入价格有误,请重新输入");
            }
        }
        System.out.println("程序结束");
    }

    public static double userInputPrice(){
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入商品定价");
        double price = sc.nextDouble();
        return price;
    }
}

二、泛型(Generic)

1、认识泛型

定义类、接口、方法时,同时声明了一个或者多个类型变量(如:<E>),称为泛型类、泛型接口、泛型方法,它们统称为泛型。

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

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

2、泛型类

基本语法:修饰符 class 类名<类型变量,类型变量,...>{ }

应用场景:在工具类中,经常会有一些方法需要处理不同类型的对象,如集合操作、数据转换等,这时可以使用泛型方法来增强工具类的通用性。

注意:类型变量用大写字母,如:T、E、K、V等。

可以控制类接收的类型变量,由于支持多个类型变量,故需注意类型变量的顺序,如:<T,E>、<E,T>之类的。

import java.util.ArrayList;

public class GenericDemo1 {
    public static void main(String[] args) {
        //认识泛型,搞清楚使用泛型的好处
        ArrayList<String> list = new ArrayList<>();
        list.add("abc");
//        list.add(123);
//        list.add(true);
//        list.add(new Object());

        //获取数据
        for(int i = 0; i < list.size(); i++){
            String rs = list.get(i);
            System.out.println(rs);

//            Object rs = list.get(i);
//            //把数据转型处理
//            String str = (String) rs;
//            System.out.println(str);
        }
    }
}
import java.util.ArrayList;

//自定义泛型类
public class MyArrayList<E> {

    private ArrayList list=new ArrayList();

    public boolean add(E e){
        list.add(e);
        return true;
    }

    public boolean remove(E e){
        return list.remove(e);
    }

    public String toString(){
        return list.toString();
    }
}

public class GenericDemo2 {
    public static void main(String[] args) {
        //学会自定义泛型类
        //模拟ArrayList集合自定义一个集合MyArrayList
        MyArrayList<String> list = new MyArrayList<>();
        list.add("abc");
        list.add("bcd");
        list.add("cde");
        list.add("def");

        System.out.println(list.remove("abc"));

        System.out.println(list);
    }
}

3、泛型接口

基本语法:修饰符 interface 接口名<类型变量,类型变量,...>{ }

4、泛型方法、通配符、上下限

1、泛型方法:定义一个方法,在方法定义中添加类型变量,然后在方法中使用类型变量。

泛型方法作用:泛型方法可以避免强制类型转换,在编译时就能够报错,同时能够确保方法接收参数的多样性,提升方法的复用性。

import demo3genericity.Student;

public class GenericDemo4 {
    public static void main(String[] args)
    {
        //学会定义泛型方法,搞清楚作用
        //打印任意数组的内容
        String[] names = {"张三","李四","王五"};
        printArray(names);

        Student[] stus=new Student[3];
        printArray(stus);

        Student max = getMax(stus);
        String max1 = getMax(names);
    }

    public static <T> void printArray(T[] names)
    {
        for (int i = 0; i < names.length; i++) {
            System.out.println(names[i]);
        }
    }

    public static <T> T getMax(T[] names)
    {
        return null;
    }
}

2、通配符与上下限

通配符是泛型类型的占位符,通配符可以接受任意类型,如:List<?>、List<? extends Car>、List<? super BYD>等。

其中泛型上限:? extends Car表示只能接受Car及其子类

其中泛型下限:? super BYD表示只能接受BYD及其父类

如果通配符是?,则能够接收所有的类型变量。

public class Car {
}

public class LX extends Car{
}

public class BYD extends Car{
}

public class Xiaomi extends Car{
}

import java.util.ArrayList;

public class GenericDemo5 {
    public static void main(String[] args)
    {
        //理解通配符和上下限
        //开发一个极品飞车游戏
        ArrayList<Xiaomi> xiaomis = new ArrayList<>();
        xiaomis.add(new Xiaomi());
        xiaomis.add(new Xiaomi());
        xiaomis.add(new Xiaomi());
        go(xiaomis);

        ArrayList<BYD> byds = new ArrayList<>();
        byds.add(new BYD());
        byds.add(new BYD());
        go(byds);

//        ArrayList<Dog> dogs = new ArrayList<>();
//        dogs.add(new Dog());
//        dogs.add(new Dog());
//        go(dogs);
    }

    //虽然小米和比亚迪是Car的子类,但是ArrayList<Xiaomi> 和 ArrayList<BYD> 和 ArrayList<Car>没有任何关系
    public static void go(ArrayList<? extends Car> cars){

    }
}

5、泛型支持的类型

泛型不支持基本数据类型,如:int、char、boolean等,但可以支持对象类型(引用数据类型)。

解释:泛型工作在编译阶段,编译阶段结束后不工作了,故泛型在编译后会被擦除,所有类型都会恢复成Object类型。

而Object类型只能接收引用类型(自定义类型或包装类),如:Integar、Character等包装类(把基本数据类型的数据包装成对象的类型)。

包装类:Integar、Character、Boolean、Byte、Short、Long、Float、Double

为什么要有包装类,包装类有哪些?

  • 为了万物皆对象,并且泛型和集合都不支持基本类型,支持包装类
  • 8种,int->Integar、char->Character,其他的都是首字母大写

包装类提供了哪些常用的功能?

  • 可以把基本类型的数据转换成字符串类型
  • 可以把字符串类型的数值转换成数值本身对应的真实数据类型

自动装箱:基本数据类型可以自动转换为包装类型。

自动拆箱:包装类型可以自动转换为基本数据类型。

import demo2genericity.MyArrayList;

import java.util.ArrayList;

public class GenericDemo6 {
    public static void main(String[] args)
    {
        //搞清楚泛型和集合不支持基本数据类型,只能支持对象类型(引用数据类型)
        //ArrayList<int> list=new ArrayList<>();
        //泛型擦除:泛型工作在编译阶段,等编译后泛型就没用了,所以泛型在编译后都会被擦除,所以类型会恢复成Object类型

        //把基本数据类型变成包装类对象
        //手工包装:
        //Integer i=new Integer(10);//过时
        Integer it1=Integer.valueOf(130);//推荐的
        Integer it2=Integer.valueOf(130);
        System.out.println(it1==it2);

        //自动包装:基本数据类型的数据可以直接变成包装对象的数据,不需要额外做任何事情
        Integer it3=130;
        Integer it4=130;
        System.out.println(it3==it4);

        //自动拆箱:把包装类型的对象直接给基本类型的数据
        int i=it3;
        System.out.println(i);

        ArrayList<Integer> list=new ArrayList<>();
        list.add(10);//自动装箱
        list.add(20);

        int rs=list.get(0);//自动拆箱

        //包装类新增的功能
        //1、可以把基本类型的数据转换成字符串
        int j=23;
        String rs1=Integer.toString(j);//"23"
        System.out.println(rs1+1);//231

        Integer i2=j;
        String rs2=i2.toString();//"23"
        System.out.println(rs2+1);//231

        String rs3=j+"";
        System.out.println(rs3+1);//231

        //2、把字符串数值转换成对应的基本数据类型(很有用)
        String str="123";
        //int rs4=Integer.parseInt(str);//123
        int rs4=Integer.valueOf(str);//123
        System.out.println(rs4+1);//124
    }
}

三、集合框架

1、认识集合

  • 集合是一种容器,用来装数据的,类似于数组,但集合的大小可变,开发中也非常常用。

两类集合:单列集合、双列集合。

  • Collection代表单列集合,每个元素(数据)只包含一个值。
  • Map代表双列集合,每个元素包含两个值(键值对)。
  • Collection<E>、List<E>、Set<E>和Map<K,V>只是接口,其子类都是其实现类。

Collection集合特点

  • List系列集合:添加的元素是有序、可重复、有索引的。
    • ArrayList、LinkedList:有序、可重复、有索引。
  • Set系列集合:添加的元素是无序、不重复、无索引的。
    • HashSet:无序、不重复、无索引。
    • LinkedHashSet:有序、不重复、无索引。
    • TreeSet:按照大小默认升序排序、不重复、无索引。
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class CollectionDemo1 {
    public static void main(String[] args) {
        //搞清楚Collection集合的整体特点
        //1、List家族的集合:有序、可重复、有索引
        List<String> list=new ArrayList<>();
        list.add("Java");
        list.add("Java");
        list.add("C");
        list.add("C++");
        System.out.println(list);//顺序和添加顺序一致
        String rs=list.get(0);
        System.out.println(rs);

        //2、Set家族的集合:无序、不可重复、无索引
        Set<String> set=new HashSet<>();
        set.add("鸿蒙");
        set.add("Java");
        set.add("Java");
        set.add("C");
        set.add("C++");
        System.out.println(set);
    }
}

2、Collection集合

1、常用功能

Collection是单列集合的祖宗,它规定的方法(功能)是全部单列集合都会继承的。

Collection方法名说明
public boolean add(E e)把元素e添加到集合中,并返回true
public void clear()清空集合中的元素
public boolean remove(E e)删除集合中元素e,并返回true
public boolean contains(E e)判断集合中是否包含元素e,返回true
public boolean isEmpty()判断集合是否为空,返回true
public int size()返回集合中元素的个数
public Object[] toArray()把集合中的元素,存储到数组中
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

public class CollectionDemo2 {
    public static void main(String[] args) {
        //搞清楚Collection提供的通用集合功能
        Collection<String> c=new ArrayList<>();
        //添加元素
        c.add("Java");
        c.add("C");
        c.add("C++");
        System.out.println(c);
        //获取集合的元素个数
        int size=c.size();
        System.out.println(size);
        //删除集合元素
        c.remove("C");
        System.out.println(c);
        //判断集合是否为空
        boolean empty=c.isEmpty();
        System.out.println(empty);
        //清空集合
//        c.clear();
//        System.out.println(c);
        //判断集合中是否存在某个数据
        boolean b=c.contains("Java");
        System.out.println(b);
        //把集合转换成数组
        Object[] arr=c.toArray();
        System.out.println(Arrays.toString(arr));

        String[] arr2=c.toArray(String[]::new);
    }
}

2、三种遍历方式

Collection的遍历方式之一:迭代器遍历:Iterator e=collection.iterator();

迭代器是用来遍历集合的专用方式(数组没有迭代器),在Java中迭代器的代表是Iterator

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionTraversalDemo3 {
    public static void main(String[] args) {
        //掌握Collection的遍历方式一:迭代器遍历
        Collection<String> names = new ArrayList<>();
        names.add("林青霞");
        names.add("张曼玉");
        names.add("王祖贤");
        names.add("柳岩");
        System.out.println(names);

        //1、得到这个集合的迭代器对象
        Iterator<String> it = names.iterator();
//        System.out.println(it.next());
//        System.out.println(it.next());
//        System.out.println(it.next());
//        System.out.println(it.next());
        //2、使用一个while循环来遍历
        while(it.hasNext()){
            String name = it.next();
            System.out.println(name);
        }
    }
}

Collection的遍历方式二:增强for循环:for(元素数据类型 变量名:数组或者集合名){ }

  • 增强for可以用来遍历集合或者数组。
  • 增强for遍历集合,本质就是迭代器遍历集合的简化写法。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionTraversalDemo4 {
    public static void main(String[] args) {
        //掌握Collection的遍历方式二:增强for
        Collection<String> names = new ArrayList<>();
        names.add("林青霞");
        names.add("张曼玉");
        names.add("王祖贤");
        names.add("柳岩");
        System.out.println(names);

        for (String name : names) {
            System.out.println(name);
        }

        String[] users = {"张三丰","张无忌","张翠山","张天师"};
        for (String user : users) {
            System.out.println(user);
        }
    }
}

Collection集合的遍历方式三:Lambda表达式:集合对象名.forEach(E e)

import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;

public class CollectionTraversalDemo5 {
    public static void main(String[] args) {
        //掌握Collection的遍历方式三:lambda
        Collection<String> names = new ArrayList<>();
        names.add("林青霞");
        names.add("张曼玉");
        names.add("王祖贤");
        names.add("柳岩");
        System.out.println(names);

//        names.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        });

//        names.forEach(s-> System.out.println(s));

        names.forEach(System.out::println);
    }
}

3、三种遍历方式的区别

遍历集合的同时又存在增删集合元素的行为时可能出现业务异常,这种现象被称之为并发修改异常问题。

解决并发修改异常问题的方案

1、如果集合支持索引,可以使用for循环遍历,没删除数据后做i--,或者可以倒着遍历。

2、可以使用迭代器遍历,并用迭代器提供的删除方法删除数据。

注意:增强for循环/Lambda遍历均不能解决并发修改异常问题,因此它们只适合做数据的遍历,不适合同时做增删操作。

import java.util.ArrayList;
import java.util.Iterator;

public class CollectionTraversalDemo6 {
    public static void main(String[] args) {
        //认识并发修改问题,搞清楚每种遍历的区别
        ArrayList<String> list = new ArrayList<>();
        list.add("Java入门");
        list.add("宁夏枸杞");
        list.add("黑枸杞");
        list.add("人字拖");
        list.add("特级枸杞");
        list.add("枸杞子");
        list.add("西洋参");
        System.out.println(list);

        //需求1:删除全部枸杞
//        for (int i = 0; i < list.size(); i++) {
//            String rs = list.get(i);
//            if(rs.contains("枸杞")){
//                list.remove(rs);
//            }
//        }
//        System.out.println(list);//出现并发修改异常问题
        //[Java入门, 宁夏枸杞, 黑枸杞, 人字拖, 特级枸杞, 枸杞子, 西洋参]
        //[Java入门, 黑枸杞, 人字拖, 枸杞子, 西洋参]

        for (int i = 0; i < list.size(); i++) {
            String rs = list.get(i);
            if(rs.contains("枸杞")){
                list.remove(rs);
                i--;//解决方案1:删除数据后做一步i--操作
            }
        }
        System.out.println(list);

        ArrayList<String> list2 = new ArrayList<>();
        list2.add("Java入门");
        list2.add("宁夏枸杞");
        list2.add("黑枸杞");
        list2.add("人字拖");
        list2.add("特级枸杞");
        list2.add("枸杞子");
        list2.add("西洋参");
        System.out.println(list2);

        //需求1、删除全部枸杞
        //解决方案2:倒着遍历并删除(前提是支持索引)
        for (int i = list2.size()-1; i >= 0; i--) {
            String rs = list2.get(i);
            if(rs.contains("枸杞")){
                list2.remove(rs);
            }
        }
        System.out.println(list2);

        ArrayList<String> list3 = new ArrayList<>();
        list3.add("Java入门");
        list3.add("宁夏枸杞");
        list3.add("黑枸杞");
        list3.add("人字拖");
        list3.add("特级枸杞");
        list3.add("枸杞子");
        list3.add("西洋参");
        System.out.println(list3);

        //需求1、删除全部枸杞
        //方案一:迭代器遍历并删除默认也存在并发修改异常问题
        //可以解决:使用迭代器自己的方法来删除
        Iterator<String> it = list3.iterator();
        while(it.hasNext()){
            String rs = it.next();
            if(rs.contains("枸杞")){
                it.remove();
            }
        }
        System.out.println(list3);

        ArrayList<String> list4 = new ArrayList<>();
        list4.add("Java入门");
        list4.add("宁夏枸杞");
        list4.add("黑枸杞");
        list4.add("人字拖");
        list4.add("特级枸杞");
        list4.add("枸杞子");
        list4.add("西洋参");
        System.out.println(list4);

        //需求1、删除全部枸杞
        //方案二和三:用增强for还有Lambda(都没有办法解决并发修改异常问题)
        //结论:增强for和Lambda只适合做遍历,不适合做遍历并修改操作
//        for (String rs : list4) {
//            if(rs.contains("枸杞")){
//                list4.remove(rs);
//            }
//        }
//        list4.forEach(rs -> {
//            if(rs.contains("枸杞")){
//                list4.remove(rs);
//            }
//        });
        System.out.println(list4);
    }
}

3、List集合

1、List的特点、特有功能

List系列集合特点:有序,可重复,有索引。

  • ArrayList:有序,可重复,有索引。
  • LinkedList:有序,可重复,有索引。

底层实现不同,适合的场景不同!

  • List集合因为支持索引,所以多了很多与索引相关的方法,当然,Collection的功能List也都继承了。
方法名称说明
void add(int index,E e)在指定位置插入元素e
E remove(int index)删除指定位置的元素e,返回被删除的元素
E set(int index,E e)修改指定位置的元素e,返回被修改的元素
E get(int index)获取指定位置的元素e

List集合支持的遍历方式:

1、for循环(因为List集合有索引)

2、迭代器

3、增强for循环

4、Lambda表达式

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListDemo1 {
    public static void main(String[] args)
    {
        //掌握List系列集合独有的功能
        List<String> names = new ArrayList<>();

        //添加数据
        names.add("张三");
        names.add("李四");
        names.add("王五");
        System.out.println(names);

        //给第三个位置插入一个数据
        names.add(2,"赵六");
        System.out.println(names);

        //删除李四
        names.remove("李四");
        System.out.println(names);

        //把王五修改成:金毛
        names.set(2,"金毛");
        System.out.println(names);

        //获取张三
        String name=names.get(0);
        System.out.println(name);

        System.out.println("--------------------------");


        //1、for循环
        for (int i = 0; i < names.size(); i++) {
            String name1 = names.get(i);
            System.out.println(name1);
        }

        //2、迭代器
        Iterator<String> it = names.iterator();
        while(it.hasNext()){
            String name2 = it.next();
            System.out.println(name2);
        }

        //3、增强for循环
        for (String name3 : names) {
            System.out.println(name3);
        }

        //Lambda
        names.forEach(name4 -> System.out.println(name4));
    }
}

2、ArrayList底层原理

ArrayList和LinkedList的区别:底层采用的数据结构(存储、组织数据的方式)不同,应用场景不同。

  • ArrayList底层是基于数组存储数据的。
  • LinkedList底层是基于链表存储数据的。

基于数组存储数据:内存中连续的一块区域A,根据索引查询数据快(查询数据通过地址值和索引定位,查询任意数据耗时相同),但是增删数据效率低(可能需要把后面很多的数据进行前移)。

注意:ArrayList集合new对象的时候为空数组,第一次添加数据时,会创建一个默认大小为10的数组,每当集合元素个数超过数组大小时,会扩容成原来的1.5倍。

3、LinkedList底层原理

  • LinkedList底层是基于双链表存储数据的。

链表的特点:

链表中的数据是一个一个独立的结点组成的,结点在内存中是不连续的,每个结点包含数据值和下一个结点的地址。

  • 链表的特点1:查询慢,无论查询哪个数据都要从头开始找。
  • 链表的特点2:链表增删相对快。

基于双链表存储数据:内存中不连续的一块区域B,每个结点包含数值和上、下一个结点的地址,查询数据慢,但是增删数据效率高,同时双链表相对于单链表对首尾元素进行增删改查的速度是极快的。

LinkedList新增了:很多首尾操作的特有方法。

LinkedList的应用场景:可以用来设计队列(只在首尾增删数据),可以用来设计栈(只在栈顶增删数据)。

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ListDemo2 {
    public static void main(String[] args)
    {
        //用LinkedList做一个队列对象
        LinkedList<String> queue = new LinkedList<>();
        //入队
        queue.addLast("张三");
        queue.addLast("李四");
        queue.addLast("王五");
        System.out.println(queue);

        //出队
        System.out.println(queue.removeFirst());
        System.out.println(queue.removeFirst());
        System.out.println(queue);

        System.out.println("-----------------------------------");

        //做一个栈
        LinkedList<String> stack = new LinkedList<>();
        //压栈
        stack.push("第一颗子弹");
        stack.push("第二颗子弹");
        stack.push("第三颗子弹");
        System.out.println(stack);

        //出栈
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2249596.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

最新Linux下使用conda配置Java23或17保姆教程(附赠安装包)

随着技术的不断进步&#xff0c;越来越多的开发者开始在Linux环境下进行Java应用的开发。Java 17作为长期支持版本&#xff08;LTS&#xff09;&#xff0c;提供了许多新特性和性能改进。当然现在最新的是Java23&#xff0c;这个还作为实验版本未广泛使用。对于需要管理多个编程…

RHEL7+Oracle11.2 RAC集群-多路径(multipath+udev)安装步骤

RHEL7Oracle11.2RAC集群-多路径&#xff08;multipathudev&#xff09;安装 配置虚拟存储 使用StarWind Management Console软件&#xff0c;配置存储 dggrid1: 1g*3 Dggrid2: 1g*3 Dgsystem: 5g*1 系统表空间&#xff0c;临时表空间&#xff0c;UNDO&#xff0c;参数文件…

PyTorch 模型转换为 ONNX 格式

PyTorch 模型转换为 ONNX 格式 在深度学习领域&#xff0c;模型的可移植性和可解释性是非常重要的。本文将介绍如何使用 PyTorch 训练一个简单的卷积神经网络&#xff08;CNN&#xff09;来分类 MNIST 数据集&#xff0c;并将训练好的模型转换为 ONNX 格式。我们还将讨论 PTH …

VM Virutal Box的Ubuntu虚拟机与windows宿主机之间设置共享文件夹(自动挂载,永久有效)

本文参考如下链接 How to access a shared folder in VirtualBox? - Ask Ubuntu &#xff08;1&#xff09;安装增强功能&#xff08;Guest Additions&#xff09; 首先&#xff0c;在网上下载VBoxGuestAdditions光盘映像文件 下载地址&#xff1a;Index of http://…

CA系统(file.h---申请认证的处理)

#pragma once #ifndef FILEMANAGER_H #define FILEMANAGER_H #include <string> namespace F_ile {// 读取文件&#xff0c;返回文件内容bool readFilename(const std::string& filePath);bool readFilePubilcpath(const std::string& filePath);bool getNameFro…

【Git】Git 命令参考手册

目录 Git 命令参考手册1. 创建仓库1.1 创建一个新的本地仓库1.2 克隆一个仓库1.3 克隆仓库到指定目录 2. 提交更改2.1 显示工作目录中已修改的文件&#xff0c;准备提交2.2 将文件添加到暂存区&#xff0c;准备提交2.3 将所有已修改的文件添加到暂存区&#xff0c;准备提交2.4 …

【Linux系列】Chrony时间同步服务器搭建完整指南

1. 简介 Chrony是一个用于Linux系统的高效、精准的时间同步工具&#xff0c;通常用于替代传统的NTP&#xff08;Network Time Protocol&#xff09;服务。Chrony不仅在系统启动时提供快速的时间同步&#xff0c;还能在时钟漂移较大的情况下进行及时调整&#xff0c;因此广泛应…

数据库日志

MySQL中有哪些日志 1&#xff0c;redo log重做日志 redo log是物理机日志&#xff0c;因为它记录的是对数据页的物理修改&#xff0c;而不是SQL语句。 作用是确保事务的持久性&#xff0c;redo log日志记录事务执行后的状态&#xff0c;用来恢复未写入 data file的已提交事务…

【vue for beginner】Vue该怎么学?

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 vue2 和 vue3 Vue2现在正向vue3逐渐更新中&#xff0c;官方vue2已经不再更新。 这个历程和当时的pyt…

【Ubuntu 24.04】How to Install and Use NVM

参考 下载 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash激活 Activate NVM: Once the installation script completes, you need to either close and reopen the terminal or run the following command to use nvm immediately. exp…

SeggisV1.0 遥感影像分割软件【源代码】讲解

在此基础上进行二次开发&#xff0c;开发自己的软件&#xff0c;例如&#xff1a;【1】无人机及个人私有影像识别【2】离线使用【3】变化监测模型集成【4】个人私有分割模型集成等等&#xff0c;不管是您用来个人学习 还是公司研发需求&#xff0c;都相当合适&#xff0c;包您满…

Python轴承故障诊断 (21)基于VMD-CNN-BiTCN的创新诊断模型

往期精彩内容&#xff1a; Python-凯斯西储大学&#xff08;CWRU&#xff09;轴承数据解读与分类处理 Pytorch-LSTM轴承故障一维信号分类(一)-CSDN博客 Pytorch-CNN轴承故障一维信号分类(二)-CSDN博客 Pytorch-Transformer轴承故障一维信号分类(三)-CSDN博客 三十多个开源…

使用docker搭建hysteria2服务端

源链接&#xff1a;https://github.com/apernet/hysteria/discussions/1248 官网地址&#xff1a;https://v2.hysteria.network/zh/docs/getting-started/Installation/ 首选需要安装docker和docker compose 切换到合适的目录 cd /home创建文件夹 mkdir hysteria创建docke…

基于Java实现的潜艇大战游戏

基于Java实现的潜艇大战游戏 一.需求分析 1.1 设计任务 本次游戏课程设计小组成员团队合作的方式&#xff0c;通过游戏总体分析设计&#xff0c;场景画面的绘制&#xff0c;游戏事件的处理&#xff0c;游戏核心算法的分析实现&#xff0c;游戏的碰撞检测&#xff0c;游戏的反…

课题组自主发展了哪些CMAQ模式预报相关的改进技术?

空气污染问题日益受到各级政府以及社会公众的高度重视&#xff0c;从实时的数据监测公布到空气质量数值预报及预报产品的发布&#xff0c;我国在空气质量监测和预报方面取得了一定进展。随着计算机技术的高速发展、空气污染监测手段的提高和人们对大气物理化学过程认识的深入&a…

深入解析下oracle date底层存储方式

之前我们介绍了varchar2和char的数据库底层存储格式&#xff0c;今天我们介绍下date类型的数据存储格式&#xff0c;并通过测试程序快速获取一个日期。 一、环境搭建 1.1&#xff0c;创建表 我们还是创建一个测试表t_code&#xff0c;并插入数据&#xff1a; 1.2&#xff0c;…

【论文复现】SRGAN

1. 项目结构 如何生成文件夹的文件目录呢? 按住shift键,右击你要生成目录的文件夹,选择“在此处打开Powershell窗口” 在命令窗口里输入命令“tree”,按回车。就会显示出目录结构。 ├─.idea │ └─inspectionProfiles ├─benchmark_results ├─data │ ├─test …

Kubernetes 之 Ingress 和 Service 的异同点

1. 概念与作用 1.1 Ingress Ingress 是什么&#xff1f; Ingress主要负责七层负载&#xff0c;将外部 HTTP/HTTPS 请求路由到集群内部的服务。它可以基于域名和路径定义规则&#xff0c;从而将外部请求分配到不同的服务。 ingress作用 提供 基于 HTTP/HTTPS 的路由。 支持 …

结构体详解+代码展示

系列文章目录 &#x1f388; &#x1f388; 我的CSDN主页:OTWOL的主页&#xff0c;欢迎&#xff01;&#xff01;&#xff01;&#x1f44b;&#x1f3fc;&#x1f44b;&#x1f3fc; &#x1f389;&#x1f389;我的C语言初阶合集&#xff1a;C语言初阶合集&#xff0c;希望能…

Springboot项目搭建(7)

1.概要 2.Layout主页布局 文件地址&#xff1a;src\views\Layout.vue 2.1 script行为模块 从elementUI中选取图标图案。 <script setup> import {Management,Promotion,UserFilled,User,Crop,EditPen,SwitchButton,CaretBottom } from "element-plus/icons-vue…