Java 入门指南:异常处理(Exception Handling)

news2024/11/15 11:09:09

异常处理是一种处理运行时错误的机制,是处理运行时错误的有效方法之一,这样可以保留应用程序的常规流程。

Java为异常设计了一套 异常处理机制(Exception Handling),当程序运行过程中发生一些异常情况时,程序不会返回任何值,而是抛出封装了错误信息的异常对象。这样保证程序代码更加优雅,并提高程序的健壮性。

引入异常之后,可以把错误的代码从正常代码中分离出来进行单独处理,这样使代码变得更加整洁;其次,当出现一些特殊情况时,还可以抛出一个检查异常,告知调用者让其处理。

JVM 如何处理异常

默认异常处理:无论何时在方法内部,如果发生异常,该方法都会创建一个称为异常对象的对象,并将其传递给运行时系统(JVM)。

异常对象包含异常的名称和描述,以及发生异常的程序的当前状态。创建异常对象并在运行时系统中处理它称为抛出异常。可能有一个方法列表,这些方法是为了到达发生异常的方法而调用的。这个方法的有序列表称为调用堆栈(Call Stack)。

JVM 处理异常的步骤

JVM 处理异常时将执行如下步骤:

  • 运行时系统搜索调用堆栈以查找包含可以处理发生的异常的代码块的方法。代码块称为异常处理程序。

  • 运行时系统从发生异常的方法开始搜索,并按照调用方法的相反顺序在调用堆栈中进行搜索。

  • 如果找到合适的处理程序,则将发生的异常传递给它。适当的处理程序意味着抛出的异常对象的类型与其可以处理的异常对象的类型相匹配。

  • 如果运行时系统搜索了调用堆栈上的所有方法,但没有找到合适的处理程序,则运行时系统将异常对象移交给 默认异常处理程序。抛给当前的Thread,Thread则会终止

    该异常处理程序是运行时系统的一部分。这个处理程序以以下格式打印异常信息,并异常地终止程序。

Exception in thread "xxx" Name of Exception : Description  
... ...... ..  // Call Stack
  • 如果当前 Thread 为最后一个非守护线程,且未处理异常,则会导致JVM 终止运行。

Exception Table 异常表

Exception Table异常表)是在Java字节码中的一项数据结构。它用于在方法的字节码中记录异常处理器的信息,以便在发生异常时能够正确地进行异常处理。

异常表的每一项记录了一个异常处理器,包括以下信息:

  1. start_pc:异常处理器起始的字节码指令偏移量。它表示该异常处理器在字节码中开始的位置。

  2. end_pc:异常处理器结束的字节码指令偏移量。它表示该异常处理器在字节码中结束的位置(不包括end_pc指向的指令)。

  3. handler_pc:异常处理代码块的起始字节码指令偏移量。它表示当发生异常时将跳转到的异常处理代码块的位置。

  4. catch_type:表示所捕获的异常类型。它是一个指向常量池中异常类的符号引用的索引。如果 catch_type 为0,则表示该异常处理器可以处理所有类型的异常

在方法的字节码中,异常表会按照 start_pc 从小到大的顺序排列。当执行方法过程中发生异常时,Java虚拟机会根据异常表中的信息查找匹配的异常处理器进行处理。

如果发现对应的异常处理器,就会跳转到相应的处理代码块执行;如果没有找到匹配的异常处理器,就将异常抛给上层调用者进行处理。

使用异常表的示例

使用 javap (用来拆解 class 文件的工具,和 javac 一样由 JDK 提供) 来分析如下代码(需要先使用 javac 编译)

//javap -c Main
 public static void simpleTryCatch();
    Code:
       0: invokestatic  #3    // Method testNPE:()V
       3: goto          11
       6: astore_0
       7: aload_0
       8: invokevirtual #5    
       // Method  java/lang/Exception.printStackTrace:()V
      11: return
    Exception table:
       from    to  target type
           0     3     6   Class java/lang/Exception
  • from(start_pc) 可能发生异常的起始点
  • to(end_pc) 可能发生异常的结束点
  • target (handler_pc) 上述 from 和 to 之前发生异常后的异常处理者的位置
  • type (catch_type) 异常处理者处理的异常的类信息

程序员如何处理异常

自定义异常处理(Customized Exception Handling):Java异常处理通过五个关键字进行管理:trycatchthrowthrowsfinally

认为可能引发异常的程序语句包含在 try 块中。如果在 try 块中发生异常,则抛出异常。代码可以捕获此异常(使用 catch 块)并以某种合理的方式处理它。系统生成的异常由 Java 运行时系统自动抛出。要手动抛出异常,使用关键字 throw

抛出方法的任何异常都必须由抛出子句指定。任何必须在 try 块完成后执行的代码都放在 finally 块中。

![[Pasted image 20231015013621.png]]

抓抛模型

何为"抓抛"

过程一:“抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象, 并将此对象抛出;一旦抛出对象以后,其后的代码就不再执行。

关于异常对象的产生:

  1. 系统自动生成的异常对象
  2. 手动的生成一个异常对象,并抛出(throw)

过程二:“抓”:可以理解为异常的处理方式:

  1. try-catch-finally
  2. throws

异常处理关键词

![[Exception Handling typs.png]]

  • 在 Java 中,一旦方法抛出异常,系统自动根据该异常对象寻找合适异常处理器(Exception Handler)来处理该异常,把各种不同的异常进行分类,并提供了良好的接口。

  • 当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并可以对其进行处理。

  • Java 的异常处理涉及了 5 个关键词:

    • try – 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。

    • catch – 用于捕获异常catch 用来捕获 try 语句块中发生的异常。

    • finallyfinally 语句块总是会被执行。它主要用于回收在 try 块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。

      只有 finally 块,执行完成之后,才会回来执行 try 或者 catch 块中的 return 或者 throw 语句

      如果 finally 中使用了 return 或者 throw 等终止方法的语句,则就不会跳回执行,直接停止。

      finally 遇见如下情况不会执行:

      • 在前面的代码中用了 System.exit() 退出程序。
      • finally 语句块中发生了异常。
      • 程序所在的线程死亡。
      • 关闭 CPU。
    • throw – 用于抛出异常

    • throws – 用在方法签名中,用于声明该方法可能抛出的异常

throw 抛出异常

throw在方法内部抛出一个Throwable 类型的异常。任何 Java 代码都可以通过 throw 语句抛出异常

作为一个合格的程序员,在编写程序时,必须要考虑程序出现问题的情况。

如果代码可能会引发某种错误,可以创建一个合适的异常类实例并抛出它

  • 例如,在定义方法时,方法需要接受参数。那么,当调用方法使用接受到的参数时,首先需要先对参数数据进行合法的判断,数据若不合法,就应该告诉调用者,传递合法的数据进来。这时需要使用抛出异常的方式来告诉调用者
如何抛出一个异常
  1. 创建一个异常对象。封装一些提示信息(信息可以自己编写)。
  2. throw 抛出这个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。
throw new ExceptionName(paramater);

//示例
throw new NullPointerException("要访问的arr数组不存在");

异常对象类可以为内置异常,也可以为用户自定义异常

抛出异常后,需要对异常进行处理,可以使用 try-catch 捕获处理,也可以使用 throws 继续将异常声明出去

通常,应捕获那些知道如何处理的异常,将不知道如何处理的异常继续传递下去

throws 声明异常

如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常

就像汽车在运行时可能会出现故障,汽车本身没办法处理这个故障,那就让开车的人来处理

throwsthrow 一般情况下成对出现

  • 声明异常:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理,那么必须通过throws进行声明,告知方法调用者此方法有异常,并让其去处理。

    关键字 throws 运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常)

  • 定义格式throws 语句用在方法定义时声明该方法要抛出的异常类型,如果抛出的是 Exception 异常类型,则该方法被声明为抛出所有的异常。多个异常可使用逗号分割:

public static void method() throws IOException, SQLException{
	// statements...
}

若父类的方法没有声明异常,则子类继承方法后,也不能声明异常!!!

当方法抛出异常列表的异常时,方法将不对这些类型及其子类类型的异常作处理,而抛向调用该方法的方法,由他去处理。

使用 throws 关键字将异常抛给调用者后,如果调用者不想处理该异常,可以继续向上抛出,但最终要有能够处理该异常的调用者

就像是汽车坏了,开车的人也不会修理,只能叫修车公司来修理了。

throws抛出异常的规则
  • 如果是不可查异常(unchecked exception),即 ErrorRuntimeException 或它们的子类,那么可以不使用 throws 关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。

  • 必须声明方法可抛出的任何可查异常(checked exception)。即如果一个方法可能出现受可查异常,要么用try-catch语句捕获,要么用throws子句声明将它抛出,否则会导致编译错误

  • 仅当抛出了异常,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出,而不是囫囵吞枣。

  • 调用方法必须遵循任何可查异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类

try,catch,finally 捕获异常

程序通常在运行之前不报错,但是运行后可能会出现某些未知的错误,不想异常出现导致程序终止,或者不想直接抛出到上一级,那么就需要通过 try-catch 等形式进行异常捕获,之后根据不同的异常情况来进行相应的处理。

捕获异常:Java 中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理。

异常捕获处理的方法通常有:

  • try-catch
  • try-catch-finally
  • try-finally
  • try-with-resource(在JDK1.7 Java7 中被引入)

catch语句可以有一个或多个或没有,finally至多有一个,try必要有。
三者也不能单独出现

try-catch

在一个 try-catch 语句块中可以捕获多个异常类型,并对不同类型的异常做出不同的处理。

	try{
		// 可能出现异常的代码
	} catch (FileNotFoundException e){
		// 处理 FileNotFoundException 异常
	} catch (IOException e){
		// 处理 IOException 异常
	} catch (FileNotFoundException | UnknownHostException e){
	// JDK1.7后,一个 catch 也可以捕获多种同类型异常,用 | 隔开
	// 处理 FileNotFoundException 或 UnknownHostException 异常
	}

对于多个异常,可以分别处理,也可以多个异常一次捕获,多次处理

多个异常,分别处理
public static void method(){
	// 代码块1
	try{
		// 可能出现异常的代码
	} catch (FileNotFoundException e){
		// 处理 FileNotFoundException 异常
	}

	// 代码块2
	try{
		// 可能出现异常的代码
	} catch (IOException e){
		// 处理 IOException 异常
	}
	
	// ...
}
多个异常,一次捕获,多次处理
public static void method(){
	// 其他代码
	try{
		// 可能出现异常的代码
	}catch (ArithmeticException e){
		// 处理 ArithmeticException 异常 
	}catch (ArrayIndexOutOfBoundsException e){
		// 处理 ArrayIndexOutOfBoundsException 异常 
	}catch (Exception e){
		// 处理异常
	}...
}

一次捕获,多次处理的异常处理方式,要求多个catch中的异常不能相同,并且若 catch 中的多个异常之间有子父类异常的关系,子类异常要求在上面的catch处理,父类异常在下面的catch处理

try-catch-finally

当方法中发生异常,异常处之后的代码不会再执行,如果之前获取了一些本地资源需要释放,则需要在方法正常结束时和 catch 语句中都调用释放本地资源的代码,显得代码比较繁琐,finally 语句可以解决这个问题。

try{
	// 可能出现异常的代码
} catch (Exception e){
	// 处理异常
} finally {
	// 必然执行的代码
}

执行情况

  • try 没有捕获到异常时try 语句块中的语句逐一被执行,程序将跳过 catch 语句块,执行 finally 语句块和其后的语句;

  • try 捕获到异常,catch 语句块里没有处理此异常的情况:当 try 语句块里的某条语句出现异常时,而没有处理此异常的 catch 语句块时,此异常将会抛给 JVM 处理,finally 语句块里的语句还是会被执行,但 finally 语句块后的语句不会被执行;

  • try 捕获到异常,catch 语句块里有处理此异常的情况:在 try 语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到 catch 语句块,并与 catch 语句块逐一匹配,找到与之对应的处理程序,其他的 catch 语句块将不会被执行,

    try 语句块中,出现异常之后的语句也不会被执行,catch 语句块执行完后,执行 finally 语句块里的语句,最后执行 finally 语句块后的语句;

try-finally

try-finally 可用在不需要捕获异常的代码,可以保证资源在使用后被关闭

例如,IO 流中执行完相应操作后,关闭相应资源;
使用 Lock 对象保证线程同步,通过 finally 可以保证锁会被释放;
数据库连接代码时,关闭连接操作等等

try {
	// 代码块
} finally {
	// 必定执行的代码
}

// 以Lock加锁为例
ReentrantLock lock = new ReentrantLock();
try {
	// 需要加锁的代码
} finally {
	lock.unlock(); //保证锁一定被释放
}

执行情况:

  • try块中引起异常,异常代码之后的语句不再执行,直接执行 finally 语句。

  • try块没有引发异常,则执行完 try 块就执行 finally 语句。

  • 注意在某些情况下 finally 中的语句不会执行

try-with-source

Java 类库中有许多资源需要通过 close 方法进行关闭。比如 InputStreamOutputStream 等。作为开发人员经常会忽略掉资源的关闭方法,导致内存泄漏。

在 JDK1.7 之前,try-catch-finally 语句是确保资源会被关闭的最佳方法,就算异常或者返回也一样可以关闭资源(手动关闭)。但 finally 中的 close 方法也可能抛出 Exception 从而覆盖掉原始异常

使用 try-with-resources,可以在 try 块中声明需要管理的资源,然后在程序执行完毕后自动关闭这些资源。

只要是 实现了 AutoCloseable 接口或 Closeable 接口的对象都可以使用 try-with-resource 来实现异常处理和自动关闭资源。这两个接口定义了一个 close() 方法,用于关闭资源。当 try-with-resources 结束时,会自动调用这些资源对象的 close() 方法。

try( //资源的声明和初始化
	 Resource1 res1 = new Resource1();
	 Resource2 res2 = new Resource2();
	 ...
   ){
	// 可能出现异常的代码
} catch (Exception e){
	// 处理异常
} [finally{ }]

实际上,在编译时也会进行转化为 try-catch-finally 语句。

  • 根据需要声明和初始化多个资源。这些资源的作用范围仅限于 try 块,当代码块执行完毕后会自动关闭这些资源

  • 如果在 try 块中同时声明多个资源,资源的声明顺序决定了关闭顺序,先声明的资源会先关闭

Scanner
public final class Scanner implements Iterator<String>, Closeable {
  // ...
}
public interface Closeable extends AutoCloseable {
    public void close() throws IOException;
}

try 代码块退出时,会自动调用 scanner.close 方法,和把 scanner.close 方法放在 finally 代码块中不同的是:

scanner.close 抛出异常,则会被抑制,抛出的仍然为原始异常。被抑制的异常会由 addSusppressed 方法添加到原来的异常,如果想要获取被抑制的异常列表,可以调用 getSuppressed 方法来获取。

先执行 try 还是 fianlly 的 return?

在 Java 中,无论是 try-finally 还是 try-catch-finallyfinally 块中的代码总会在try块中的 return语句执行之前执行。

具体的执行顺序如下:

  1. 如果 try 块中的 return 语句被执行,那么它会将返回值保存在一个临时位置。
  2. 接下来,finally 块中的代码会被执行。
  3. 最后,如果 finally 块中没有发生异常,那么 try 块中的 return 语句会将之前保存的返回值返回给调用者。

这意味着无论 try 块中的 return 语句是否被执行,finally 块中的代码都会在方法返回之前被执行。但需要注意的是,如果在 finally 块中发生了异常并且没有被捕获,那么该异常将会覆盖之前的异常(如果有的话)。

如果在 finally 块中使用了 return 语句,那么它会覆盖之前保存的返回值,并返回 finally 块中的返回值。因此,在 finally 块中使用 return 语句可能会导致意外的行为,应谨慎使用

自定义异常类

Java 中不同的异常类,分别表示着某一种具体的异常情况,那么在开发中,当Java内置的异常都不能明确的说明异常情况的时候,需要创建自己的异常

在开发中根据自己业务的异常情况来自己定义异常类。例如:登录系统中,年龄不能为负数,就需要自己定义一个登录异常类

如何自定义异常类

  1. 继承现有的异常类

    • 自定义一个编译期异常类(Unchecked): 自定义类并继承 java.lang.Exception

    • 自定义一个运行时期的异常类(Checked):自定义类并继承于java.lang.RuntimeException

  2. 提供全局常量 serialVersionUID:这是一个标识序列化版本的唯一标识符。可以使用默认的值 1L:"

private static final long serialVersionUID = 1L;

如果自定义异常类不会进行序列化和反序列化操作,这个常量可以省略。

  1. 提供重载的构造器:根据业务的需求,添加适当的构造方法。可以提供不同参数的构造方法,用于初始化异常消息或其他字段。

    习惯上,定义一个异常类应包含两个构造函数,一个无参构造函数和一个带有详细描述信息的构造函数ThrowabletoString 方法会打印这些详细信息,调试时很有用)

public class MyException extends Exception {
	private static final long MY_VERSION_UID = 1L;
	
	public MyException(){ }
	
	public MyException(String message){
		super(message);
		// 父类方法 getMessage()
	}
	
	//将引起异常的原因传给父类
	public MyException(String message, Throwable cause){
		super(message,cause);
		// 父类方法 getCause()
	}
}

链式异常 Chained Exception in Java

链式异常将一个异常与另一个异常联系起来,在异常处理过程中,将一个异常作为另一个异常的原因(即引发异常的根本原因)。这可以帮助我们更好地追踪和理解异常发生的原因。

例如:除以零时,方法抛出了一个 ArithmeticException,但导致异常的实际原因是导致除数为零的I/O错误。该方法只会向调用者抛出算术异常。这样调用者就不会知道异常的实际原因。链式异常在这种情况下使用。

Java 中支持链式异常的 Throwable 类的构造函数:

  • ExceptionName(Throwable cause) :直接在创建异常对象时设置原因异常,cause是导致当前异常的异常。

  • Throwable(String msg, Throwable cause):msg是异常消息,cause是导致当前异常的异常。

Java 中支持链式异常的 Throwable 类的方法:

  • wrap(Throwable cause):将原始异常包装成一个新的异常对象,并创建异常链。

  • getCause() 方法:该方法返回异常的实际原因。

  • initCause(Throwable cause) 方法:将一个异常作为另一个异常的原因。这个方法允许我们构建一个异常链。

try { 
	// 可能出现异常的代码
	throw new IllegalArgumentException("无效参数异常");
} catch (Exception e) {
	// 创建一个新的异常,将原始异常作为原因
	CustomException customexception = new CustomException()
	customexcption.initCause(e)

	throw customException;
}

通过使用异常链,我们可以逐级地追溯异常的原因和触发点,帮助调试和分析问题。在捕获异常后,可以通过调用getCause()方法来获取原因异常,并进一步分析异常链。

需要注意的是,异常链的长度是有限制的,因为每个异常都只能有一个原因。如果尝试 为一个已经有原因的异常设置新的原因,将会抛出IllegalStateException异常。

在处理链式异常时,我们应该注意以下几点:

  • 尽量保持异常的原因链不过长,以免造成不必要的复杂性。
  • 在异常的处理逻辑中,逐级检查和处理每个原因异常,以确保所有相关的异常得到适当的处理。
  • 在日志记录中,可以打印完整的异常链信息,以便进行故障排查和分析。

异常处理中的方法重载

当异常处理涉及到方法覆盖时,就会产生歧义。编译器无法识别应该遵循哪个定义。

可以为两种情况讨论:

  1. SuperClass 没有声明异常: 子类只能声明未检查的异常,而不能声明已检查的异常。

  2. 超类声明了一个异常

    • 子类只能声明超类声明的异常的相同或子异常以及任何新的运行时异常,而不是在同一级别或更高级别上的任何新的检查异常。

    • 子类也可以不声明异常

为何异常耗时

异常处理会导致额外的性能损耗:

  1. 异常对象的创建:当发生异常时,Java 会创建一个异常对象,其中包含有关异常的信息,例如堆栈跟踪和异常消息。异常对象的创建涉及内存分配和对象初始化,这些操作都需要花费一定的时间和资源。

  2. 异常处理代码的执行:当发生异常时,程序会跳转到匹配的异常处理代码块,执行与异常相关的逻辑。这可能会中断正常的程序执行流程,并涉及额外的指令执行、堆栈操作等,增加了代码的执行时间和开销。

  3. 堆栈跟踪的收集:当异常被抛出时,Java 会收集当前的调用栈信息。这包括所有调用过程中的方法名称和行号等信息。堆栈跟踪的收集需要遍历调用栈,获取信息并构建堆栈跟踪数据结构,这可能会消耗一定的时间和计算资源。

  4. 异常传播和捕获:当异常在方法之间传播时,程序必须检查异常类型并确定是否有匹配的异常处理器,以决定异常是继续传播还是被捕获处理。这个过程涉及异常的检查和匹配,可能需要遍历异常处理器列表,进行条件判断等,这些操作都需要一定的时间和开销。

实例对比

建立一个异常对象,是建立一个普通Object耗时的约20倍(实际上差距会比这个数字更大一些,因为循环也占用了时间),而抛出、接住一个异常对象,所花费时间大约是建立异常对象的4倍

public class ExceptionTest {  

    private int testTimes;  

    public ExceptionTest(int testTimes) {  
        this.testTimes = testTimes;  
    }  

    public void newObject() {  
        long l = System.nanoTime();  
        for (int i = 0; i < testTimes; i++) {  
            new Object();  
        }  
        System.out.println("建立对象:" + (System.nanoTime() - l));  
    }  

    public void newException() {  
        long l = System.nanoTime();  
        for (int i = 0; i < testTimes; i++) {  
            new Exception();  
        }  
        System.out.println("建立异常对象:" + (System.nanoTime() - l));  
    }  

    public void catchException() {  
        long l = System.nanoTime();  
        for (int i = 0; i < testTimes; i++) {  
            try {  
                throw new Exception();  
            } catch (Exception e) {  
            }  
        }  
        System.out.println("建立、抛出并接住异常对象:" + (System.nanoTime() - l));  
    }  

    public static void main(String[] args) {  
        ExceptionTest test = new ExceptionTest(10000);  
        test.newObject();  
        test.newException();  
        test.catchException();  
    }  
}

运行结果:

建立对象:575817  
建立异常对象:9589080  
建立、抛出并接住异常对象:47394475

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

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

相关文章

联华证券-美联储降息补贴:额外补贴,美元短期走势或保持稳定

市场进一步确信美联储9月的加息举措&#xff0c;即便对加息幅度的预测并不一致。 当地时间8月23日&#xff0c;美联储主席鲍威尔在Jackson Hole年度会议中发出迄今为止最强烈的降息信号&#xff1a;为避免国内劳动力市场进一步疲弱&#xff0c;美联储打算采取行动&#xff0c;…

Spring(面试篇)

目录 什么是Spring&#xff1f; Spring的两大核心概念 Spring框架的设计目标&#xff0c;设计理念&#xff0c;和核心是什么 Spring的优缺点是什么&#xff1f; Spring由哪些应用场景 Spring由哪些模块组成&#xff1f; Spring框架中都用到了那些设计模式&#xff1f; …

Battery Cycle Life Prediction From Initial Operation Data

这个例子展示了如何使用线性回归(一种监督机器学习算法)预测快速充电锂离子电池的剩余循环寿命。使用基于物理的建模方法预测锂离子电池的循环寿命是非常复杂的&#xff0c;因为不同的操作条件和显著的设备可变性&#xff0c;即使是来自同一制造商的电池。对于这种情况&#xf…

2023高教社杯数学建模国赛C题详细代码 文章 数据教学 保姆级手把手包含文档格式 2024数模国赛教学:蔬菜类商品的自动定价和补货决策

本系列专栏将包括两大块内容 第一块赛前真题和模型教学,包括至少8次真题实战教学,每期教学专栏的最底部会提供完整的资料百度网盘包括:真题、数据、可复现代码以及文章. 第二块包括赛中思路、代码、文章的参考助攻, 会提供2024年高教社国赛各个赛题的全套参考内容(一般36h内更新…

JavaWeb学习——事务管理、AOP学习

目录 一、事务管理 1、事务回顾 2、事务进阶 a、rollbackFor属性 b、propagation属性 二、AOP学习 1、基础了解 2、AOP进阶 一、事务管理 1、事务回顾 事务的概念&#xff1a;事务必须服从ACID原则。ACID指的是原子性&#xff08;atomicity&#xff09;、一致性&#xf…

Linux网络编程:多路转接--poll/epoll

1. poll poll也是一种多路转接的方案&#xff0c;解决了select的fd有上限和每次调用都要重新设置关心的fd的问题。 2. poll接口 #include int poll(struct pollfd* fds, nfds_t nfds, int timeout); 参数&#xff1a;fds&#xff1a;可以看成是动态数组/数组/结构体数组 nfds&…

【生日视频制作】一群美女挥手拉蓝横幅条幅AE模板修改文字软件生成器教程特效素材【AE模板】

一群美女挥手拉蓝条横幅生日视频制作教程AE模板修改文字生成器 怎么如何做的【生日视频制作】一群美女挥手拉蓝横幅条幅AE模板修改文字软件生成器教程特效素材【AE模板】 生日视频制作步骤&#xff1a; 安装AE软件下载AE模板把AE模板导入AE软件修改图片或文字渲染出视频

Ai+若依(系统工具-->表单构建):【02篇】

系统工具 表单构建 介绍 允许用户通过拖放等可视化操作创建表单,比如用来收集数据的表格或调查问卷。 可以自定义表单的各个部分,比如添加不同的输入项和设置验证规则,无需编写代码。 提供了导出数据、导入数据、分享表单和设置权限的功能,方便数据管理和共享。 案例 通…

RoboCopy文件快速拷贝工具

RoboCopy是Windows平台(从Windows Vista/Window 7开始)自带的文件快速拷贝工具,它是xcopy命令工具的升级版,解除了xcopy拷贝文件时4GB的容量限制,同时,又支持多线程、给文件夹制作镜像、复制指定日期的文件等功能。 1 全部拷贝 假设从alice文件夹,全部拷贝到bob文件夹,则…

leetcode 80 删除有序数组中的重复项 II

正文 仍旧使用双指针&#xff0c; 思想与 leetcode 26 删除有序数组中的重复项 一致。只是此时因为要求保留重复元素两次&#xff0c;我们的左侧指针可以从第二个数据开始&#xff0c;且右侧指针需要和两个元素的值进行判断。 class Solution:def removeDuplicates(self, nums…

WPF—资源的使用

资源的使用 资源是可以在应用中的不同位置重复使用的对象。 资源的示例包括画笔和样式。 <Window.Resources><!--定义颜色资源--><SolidColorBrush x:Key"MyBrush" Color"#05E0E9"/><!--定义样式资源--><Style TargetType&quo…

前端技术(五)—— 使用Node.js编写简单的项目

一、 初始化项目 1. 创建项目 ⑴ 新建 api_kjzt_server 文件夹作为项目根目录&#xff0c;并初始化包管理配置文件 并在项目根目录中运行如下的命令&#xff0c;初始化包管理配置文件&#xff1a; npm init -y⑵ 运行如下的命令&#xff0c;安装特定版本的 express npm i e…

企业级WEB应用服务器TOMCAT详解

一、什么是TOMCAT 1.1来源 Tomcat是Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;的Jakarta 项目中的一个核心项目&#xff0c;由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持&#xff0c;最新的Servlet 和JSP 规范总是能…

A Neural Probabilistic Language Model

摘要 统计语言建模的一个目标是学习单词序列的联合概率函数。由于维度的诅咒&#xff0c;这在本质上是困难的:我们建议用它自己的武器来对抗它。在提出的方法中&#xff0c;人们同时学习(1)每个单词的分布式表示&#xff08;词向量&#xff09;(即单词之间的相似性)以及(2)表示…

TypeScript 类型注解(二)

一、TypeScript类型约束--对象 对象其实和数组类似&#xff0c;不是限制对象本身的类型&#xff0c;而是对对象属性类型进行限制 结构简化&#xff1a; 对对象做类型限制的好处&#xff1a; 大家都学习过一段时间编程了&#xff0c;会发现咱们经常操作的类型就是对象&#xf…

使用miniconda构建数据科学环境

背景 数据科学中&#xff0c;不同时期项目代码往往是由不同的版本的python和第三方数据科学包构建&#xff0c;这些不同版本往往会存在兼容性问题&#xff0c;要运行这些代码&#xff0c;需要管理不同的版本的安装包。Conda是一个开源的包管理和环境管理系统&#xff0c;环境管…

Linux | 编译和使用自定义动静态库的全面解析

新竹高于旧竹枝&#xff0c;全凭老干为扶持。 - 《新竹》(郑燮) 2024.8.25 目录 1、静态库和动态库简介 静态库&#xff08;.a&#xff09;&#xff1a; 动态库&#xff08;.so&#xff09;&#xff1a; 动态库和静态库的比较&#xff1a; 2、静态库的生成和使用&#xff…

GCB | 首次揭示!气候变化对常绿和落叶植物物候差异化影响的机制

气候变化引起的植物物候改变已对全球范围内生物多样性和生态系统产生重大影响&#xff08;Nature高引文章 | 北京大学朴世龙院士等&#xff1a;全球变暖对植被物候的影响及其机制&#xff1b;Nature Ecology & Evolution | 南京大学张永光教授团队揭示延长的植被物候期受CO…

set容器的所有操作

1.基本概念 2.构造和赋值 3.大小和交换 4.插入和删除 5.查找和统计 6.set和multiset的区别 7.pair对组创建 用p.first和p.second调用前后两个属性。 8.仿函数实现降序排列 自定义数据类型也一样用仿函数&#xff1a;

【领域驱动设计 打通DDD最小闭环】领域建模

本篇BLOG为DDD流程的第二步&#xff0c;在模型的建立阶段&#xff0c;领域专家与技术人员通过领域建模来完成更为细致的模型建立讨论 领域建模的目的 领域建模主要有两个目的&#xff1a; 将知识可视化&#xff0c;准确、深刻地反映领域知识&#xff0c;并且在业务和技术人…