如何在项目中正确使用异常?

news2024/11/15 14:09:01

文章目录

      • 异常系列文章
      • 一、异常介绍
      • 二、异常体系
      • 三、异常处理机制
      • 四、异常处理
      • 五、异常调用链

异常系列文章

如何在项目中正确使用异常?
如何优雅的设计Java异常
Java统一异常处理–实战篇
Java 异常处理的误区和经验总结
你要的Java常见异常都在这里
Java中异常抛出后代码还会继续执行吗

一、异常介绍

异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。

比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出 java.lang.ArithmeticException 的异常。

异常发生的原因有很多,通常包含以下几大类:

  • 用户输入了非法数据。
  • 要打开的文件不存在。
  • 网络通信时连接中断,或者JVM内存溢出。

这些异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。-

要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:

  • 检查性异常: 最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
  • 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
  • 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

二、异常体系

注意:编译器对RuntimeException及其子类不做强制捕获要求,不是指应用程序本身不应该捕获并处理RuntimeException。是否需要捕获,具体问题具体分析。

Java中定义了很多现成的异常(叫做内建异常),这些异常又分属不同类别,不同类别的异常具有不同的特点。整个Java的异常体系(类图)如下图所示。

img

下面将详细讲述这些异常之间的区别与联系:

  • ErrorError类对象由 Java 虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。例如,Java虚拟机运行错误(Virtual MachineError),当JVM不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止;还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在Java中,错误通常是使用Error的子类描述。
  • Exception
    • Exception分支中有一个重要的子类RuntimeException(运行时异常),该类型的异常自动为你所编写的程序定义ArrayIndexOutOfBoundsException(数组下标越界)、NullPointerException(空指针异常)、ArithmeticException(算术异常)、MissingResourceException(丢失资源)、ClassNotFoundException(找不到类)等异常,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生;
    • RuntimeException之外的异常我们统称为非运行时异常,类型上属于Exception类及其子类,从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOExceptionSQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

下面的表中列出了 Java 的非检查性异常。

异常描述
ArithmeticException当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。
ArrayIndexOutOfBoundsException用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。
ArrayStoreException试图将错误类型的对象存储到一个对象数组时抛出的异常。
ClassCastException当试图将对象强制转换为不是实例的子类时,抛出该异常。
IllegalArgumentException抛出的异常表明向方法传递了一个不合法或不正确的参数。
IllegalMonitorStateException抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。
IllegalStateException在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。
IllegalThreadStateException线程没有处于请求操作所要求的适当状态时抛出的异常。
IndexOutOfBoundsException指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
NegativeArraySizeException如果应用程序试图创建大小为负的数组,则抛出该异常。
NullPointerException当应用程序试图在需要对象的地方使用 null 时,抛出该异常
NumberFormatException当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
SecurityException由安全管理器抛出的异常,指示存在安全侵犯。
StringIndexOutOfBoundsException此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。
UnsupportedOperationException当不支持请求的操作时,抛出该异常。

下面的表中列出了 Java 定义在 java.lang 包中的检查性异常类。

异常描述
ClassNotFoundException应用程序试图加载类时,找不到相应的类,抛出该异常。
CloneNotSupportedException当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。
IllegalAccessException拒绝访问一个类的时候,抛出该异常。
InstantiationException当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。
InterruptedException一个线程被另一个线程中断,抛出该异常。
NoSuchFieldException请求的变量不存在
NoSuchMethodException请求的方法不存在

自定义异常跟大多数内建异常一样,要么作为受检异常继承自Exception,要么作为非受检异常继承自RuntimeException。那么,在定义某个异常时,我们应该选择让其继承自Exception呢?还是应该选择让其继承自RuntimeException呢?

  • 对于代码bug(比如数组越界)以及不可恢复异常(比如数据库连接失败),即便我们捕获了,也做不了太多事情,所以,我们倾向于使用非受检异常。
  • 对于可恢复异常、业务异常、预期可能发生的异常,比如提现金额大于余额的异常,我们更倾向于使用受检异常,明确告知调用者需要捕获处理。

三、异常处理机制

Java的异常处理本质上是抛出异常捕获异常

  • 抛出异常:要理解抛出异常,首先要明白什么是异常情形(exception condition),它是指阻止当前方法或作用域继续执行的问题。其次把异常情形和普通问题相区分,普通问题是指在当前环境下能得到足够的信息,总能处理这个错误。对于异常情形,已经无法继续下去了,因为在当前环境下无法获得必要的信息来解决问题,你所能做的就是从当前环境中跳出,并把问题提交给上一级环境,这就是抛出异常时所发生的事情。抛出异常后,会有几件事随之发生。首先,是像创建普通的java对象一样将使用new在堆上创建一个异常对象;然后,当前的执行路径(已经无法继续下去了)被终止,并且从当前环境中弹出对异常对象的引用。此时,异常处理机制接管程序,并开始寻找一个恰当的地方继续执行程序,这个恰当的地方就是异常处理程序或者异常处理器,它的任务是将程序从错误状态中恢复,以使程序要么换一种方式运行,要么继续运行下去。

举个简单的例子,假使我们创建了一个学生对象Student的一个引用stu,在调用的时候可能还没有初始化。所以在使用这个对象引用调用其他方法之前,要先对它进行检查,可以创建一个代表错误信息的对象,并且将它从当前环境中抛出,这样就把错误信息传播到更大的环境中。

if(stu == null){
    throw new NullPointerException();
}

这就抛出了异常,它将在其他的地方得到执行或者处理,具体是哪个地方后面将很快介绍,代码中出现的 throw 是一个关键字,暂时先不做过多讲解,后面会详细讲解。

  • 捕获异常:在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。

提示

对于运行时异常错误检查异常,Java技术所要求的异常处理方式有所不同。

由于运行时异常及其子类的不可查性,为了更合理、更容易地实现应用程序,Java规定,运行时异常将由Java运行时系统自动抛出,允许应用程序忽略运行时异常

对于方法运行中可能出现的Error,当运行方法不欲捕捉时,Java允许该方法不做任何抛出声明。因为,大多数Error异常属于永远不能被允许发生的状况,也属于合理的应用程序不该捕捉的异常。

对于所有的检查异常,Java规定:一个方法必须捕捉,或者声明抛出方法之外。也就是说,当一个方法选择不捕捉检查异常时,它必须声明将抛出异常。

Java异常处理涉及到五个关键字,分别是:trycatchfinallythrowthrows。下面将骤一介绍,通过认识这五个关键字,掌握基本异常处理知识。

try – 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。
  • catch – 用于捕获异常。catch用来捕获try语句块中发生的异常。
  • finally – finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
  • throw – 用于抛出异常。
  • throws – 用在方法签名中,用于声明该方法可能抛出的异常。

四、异常处理

当某段程序抛出异常时,我们应该如何处理抛出的异常呢?一般来讲,我们有3种处理方法。

除了下面的处理方式,也可以结合这个一起参考:

总之,如果你捕获了异常打算处理的话,除了通过日志正确记录异常原始信息外,通常还有三种处理模式:(catch 捕获处理异常的一些最佳实践。)

  • 转换,即转换新的异常抛出。对于新抛出的异常,最好具有特定的分类和明确的异常消息,而不是随便抛一个无关或没有任何信息的异常,并最好通过 cause 关联老异常。
  • 重试,即重试之前的操作。比如远程调用服务端过载超时的情况,盲目重试会让问题更严重,需要考虑当前情况是否适合重试。
  • 恢复,即尝试进行降级处理,或使用默认值来替代原始数据

3种错误方式

1、捕获了异常后直接生吞·

2、丢弃异常的原始信息

3、抛出异常时不指定任何消息

正确:

处理异常应该杜绝生吞,并确保异常栈信息得到保留。如果需要重新抛出异常的话,请使用具有意义的异常类型和异常消息

1)捕获后记录日志

public void f() throws LowLevelException { ... }
public void g() {
  try {
    f();
  } catch(LowLevelException e) {
    log.warn("...", e); //使用日志框架记录日志
  }
}

2)原封不动再抛出

public void f() throws LowLevelException { ... }
//如果LowLevelException是非受检异常,则不需要在函数g()定义中声明
public void g() throws LowLevelException {
  f();
}

3)包装成新异常抛出

public void f() throws LowLevelException { ... }
public void g() {
  try {
    f();
  } catch(LowLevelException e) {
    throw new HighLevelException("...", e);
  }
}

以上我们介绍了3种处理异常的方法,那么,当代码抛出异常时,我们应该选择哪一种来处理方法呢?很多程序员对处理方式的选择比较随意,也没有一个原则。实际上,选择哪种处理方法,其实有一个简单的原则可以参考,那就是:函数只抛出跟函数所涉及业务相关的异常。

在函数内部,如果某块代码的异常行为,并不会导致调用此函数的上层代码出现异常行为,也就是说,上层代码并不关心被调用函数内部的这个异常,我们就可以在函数内部将这个异常“消化掉”:将其捕获并打印日志记录。相反,如果函数内部的异常行为会导致调用此函数的上层代码出现异常行为,那么,我们就必须让上层代码感知到此异常的存在。如果此异常跟函数的业务相关,上层代码在调用此函数时,知道如何处理此异常,那么直接将其抛出就可。如果此异常跟函数的业务无关,上层代码无法理解这个异常的含义,不知道如何处理,那么需要将其包裹成新的跟函数业务相关的异常重新抛出。

public byte[] readData(String filePath) throws DataReadException,FileNotFoundException {
  InputStream in = null;
  try {
    Thread.sleep(10);
    in = new FileInputStream(filePath);
    byte[] data = new byte[in.available()];
    in.read(data);
    return data;
  } catch (InterruptedException e) {
    throw new DataReadException("Interrupted when reading: " + filePath, e);
  } catch (IOException e) {
    throw new DataReadException("Failed to read: " + filePath, e);
  } finally {
    if (in != null) {
      try {
        in.close();
      } catch (IOException e) {
        //使用日志框架记录日志
      }
    }
  }
}

参照刚刚给出的3种异常处理方式,以及选择的原则,我们来分析一下上面的代码。

1)调用readData()函数的上层代码并不关心文件关闭失败(对应in.close()语句)导致的IOException异常,因此,我们直接将其捕获并打印日志。

2)对于文件读取失败而抛出的IOException异常,因为IOException异常比较底层,如果原封不动抛出,那么上层代码可能并不知道如何处理,所以,我们将其重新包裹成自定义的DataReadException异常再抛出。

3)同理,对于因sleep()函数被中断而抛出的InterruptedException异常,上层代码也无法理解,因此,我们同样将其包裹为DataReadException异常再抛出。

4)对于文件打开失败而抛出的FileNotFoundException异常,因为跟readData()函数业务相关,毕竟readData()函数中的参数就是文件的路径,所以,我们可以直接将其抛出。当然,如果我们想要减少readData()函数受检异常的个数,那么也可以将FileNotFoundException异常统一包裹为DataReadException异常再抛出。

五、异常调用链

异常最终的宿命终究是被捕获并打印异常信息,以便程序员debug问题,比如将其打印到日志或命令行中。为了给程序员展示充足的异常信息,我们一般需要将异常调用链完整打印出来。

异常调用链记录了异常引起的整个过程,当前被捕获的异常是由哪个异常引起的,跟函数调用一样,一直追溯到引起整个异常调用链的最原始的异常为止。除此之外,异常调用链还会记录每个异常的生命周期内所经历的所有函数。异常的生命周期指的是,异常从创建到被捕获并不再继续抛出的这一过程。

public class Demo17_1 {
  public static class LowLevelException extends Exception {
    public LowLevelException() { super(); }
    public LowLevelException(String msg, Throwable cause) { super(msg, cause); }
    public LowLevelException(String msg) { super(msg); }
    public LowLevelException(Throwable cause) { super(cause); }
  }

  public static class MidLevelException extends Exception {
    //...与LowLevelException实现类似,省略代码实现...
  }

  public static class HighLevelException extends RuntimeException {
    //...与LowLevelException实现类似,省略代码实现...
  }

  public static void fa() throws LowLevelException {
    throw new LowLevelException("LowLevelException-msg");
  }

  public static void fb() throws LowLevelException {
    fa();
  }

  public static void fc() throws MidLevelException {
    try {
      fb();
    } catch (LowLevelException e) {
      throw new MidLevelException("MidLevelException-msg", e);
    }
  }

  public static void fd() {
    try {
      fc();
    } catch (MidLevelException e) {
      throw new HighLevelException("HighLevelException-msg", e);
    }
  }

  public static void fe() {
      fd();
  }
  
  public static void main(String[] args) {
    try {
      fe();
    } catch(HighLevelException e) {
      e.printStackTrace();
    }
  }
}

我们分析一下上述代码。

1)LowLevelException异常为调用链中的第一个异常,在fa()函数中抛出,fb()未捕获直接将其抛出,fc()将其捕获并且重新包装成MidLevelException异常抛出,所以,LowLevelException异常的生命周期经历了3个函数:fa()、fb()、fc()。

2)MidLevelException异常在fc()函数中创建,在fd()函数中被捕获,然后重新包装成HighLevelException异常抛出,所以,MidLevelException()异常的生命周期经历了2个函数:fc()和fd()。

3)HighLevelException异常为运行时异常,在fd()函数中创建,fe()函数没有将其捕获,默认原样抛出,最终被main()函数捕获并输出异常调用链信息,至此异常调用链结束。所以,HighLevelException异常的生命周期经历了3个函数:fd()、fe()、main()。

HighLevelException异常由MidLevelException异常引起,MidLevelException异常又由LowLevelException异常引起,因此,上述代码打印出来的异常调用链,如下所示。

demo.Demo17_1$HighLevelException: HighLevelException-msg
	at demo.Demo17_1.fd(Demo17_1.java:53)
	at demo.Demo17_1.fe(Demo17_1.java:58)
	at demo.Demo17_1.main(Demo17_1.java:27)
Caused by: demo.Demo17_1$MidLevelException: MidLevelException-msg
	at demo.Demo17_1.fc(Demo17_1.java:45)
	at demo.Demo17_1.fd(Demo17_1.java:51)
	... 2 more
Caused by: demo.Demo17_1$LowLevelException: LowLevelException-msg
	at demo.Demo17_1.fa(Demo17_1.java:34)
	at demo.Demo17_1.fb(Demo17_1.java:38)
	at demo.Demo17_1.fc(Demo17_1.java:43)
	... 3 more

异常调用链可以完整的描述异常发生的整个过程。**但需要特别注意的是,捕获异常并包裹成新的异常抛出时,我们一定要将先前的异常通过cause参数传递进新的异常,否则,异常调用链将会断开。**比如,对于上述示例代码,在创建MidLevelException异常时,如果我们没有将LowLevelException异常通过cause参数传递给MidLevelException,那么,通过MidLevelException异常将无法再追踪到LowLevelException异常。最终打印出来的异常调用链将只包含HighLevelException异常信息和MidLevelException异常信息。

//错误做法
try {
  ...
} catch (CausedByException e) {
  throw new NewException("msg..."); // e丢失
}

//正确的做法
try {
  ...
} catch (CausedByException e) {
  throw new NewException("msg...", e);
}

在平时的开发中,我们还需要特别注意,对于异常的处理,要么记录,要么抛出,但两者不能同时执行。错误的做法如下所示。在异常调用链中,我们只需要在最后一个异常生命周期结束时,打印异常调用链即可,没必要像如下所示,重复打印部分异常调用链。既然我们已经抛出了异常,异常就理应由上层函数来负责处理(比如打印)。

//错误的做法
try {
  ...
} catch (CausedByException e) {  
   logger.error("...", e);
   throw new NewException("msg...", e);
}

参考文章:
部分内容参考于 https://www.xzgedu.com/ Java编程之美专栏

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

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

相关文章

SpringBoot后端接口请求参数映射方式详解

在SpringBoot项目中,前端HTTP请求中的参数如何映射到Controller层的接口方法中的参数?这里针对各种方式做一个测试与总结。 1:QueryString方式 QueryString参数传递的方式为,在请求URL中直接拼接请求参数如:URL?para…

Java实现调用ChatGPT详解

Java调用ChatGPT的小插件1. 申请ChatGPT账号2. 配置阶段2.1 依赖引入2.2 配置application.yml文件2.3 EnableChatGPT注解3. 使用4. 测试1. 申请ChatGPT账号 CSDN上面有很多申请ChatGPT账号的教程,可以直接搜索chatgpt账号注册,然后按照高赞的几个回答注…

谷粒商城--SPU和SKU

目录 1.SPU和SKU概念 2.表的关系理解 3.导入前端代码 4.完善后端接口 5.属性分组详情 6.规格参数详情 7. 销售属性详情 8.分组与属性关联 9.发布商品 10.仓库服务 1.SPU和SKU概念 SPU:standard product unit(标准化产品单元):是商品信息聚合的…

链表OJ(一)

目录 从尾到头打印链表_牛客题霸_牛客网 160. 相交链表 141. 环形链表 142. 环形链表 II 138. 复制带随机指针的链表 从尾到头打印链表_牛客题霸_牛客网 输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)。 如输入…

Three.js中的3D文字效果

对于一些设计网页中经常会出现一些3D的文字效果,本文将利用Three.js实现各种动画WebGL文本输入效果。 示例效果 原文章 文本采样 通常情况下,文本网格是2D的平面形状,我们所要实现的3D文本形状则是要在2D的平面下,再生成z值形成…

Oracle数据库启停命令

在日常工作中,关于数据库的启停:   先关闭上层应用服务 --> 关闭监听 --> 关闭数据库;   启动数据库 --> 启动监听 --> 启动应用(Oracle SQL Developer)。 监听lsnrctl Oracle监听命令。 lsnrctl start [listener-name]&a…

Xml格式化与高亮显示

具体请参考:Xml格式化与高亮显示

分布式系统的数据一致性方案

1、在出现一致性问题时如果系统的并发或不一致情况较少,可以先使用重试来解决 a、同步重试 b、异步重试 c、入库,定时任务重试 2、分布式事务 基于数据库 XA 协议的 2PC、3PC,基于业务层的TCC,基于消息队列消息表的最终一致性方案&#xff0…

七大设计原则之接口隔离原则应用

目录1 接口隔离原则介绍2 接口隔离原则应用1 接口隔离原则介绍 接口隔离原则(Interface Segregation Principle, ISP)是指用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口。这个原则指导我们在设计接口时…

八、Git远程仓库操作——跨团队成员的协作

前言 前面一篇博文介绍了git团队成员之间的协作,现在在介绍下如果是跨团队成员的话,如何协作? 跨团队成员协作,其实就是你不属于那个项目的成员,你没有权限向那个仓库提交代码。但是github还有另一种 pull request&a…

图形化深度学习开发平台PaddleStudio(代码开源)

目录一、PaddleStudio概述二、环境准备2.1 安装PaddlePaddle2.2 安装依赖库三、基本使用介绍3.1 启动3.2 快速体验3.2.1 下载示例项目3.2.2 训练3.2.3 评估3.2.4 测试3.2.5 静态图导出四、数据集格式4.1 图像分类4.2 目标检测4.3 语义分割4.4 实例分割五、趣味项目实战&#xf…

【前端笔试题二】从一个指定数组中,每次随机取一个数,且不能与上次取数相同,即避免相邻取数重复

前言 本篇文章记录下我在笔试过程中遇到的真实题目,供大家参考。 1、题目 系统给定一个数组,需要我们编写一个函数,该函数每次调用,随机从该数组中获取一个数,且不能与上一次的取数相同。 2、思路解析 数组已经有了…

Java编译过程、JIT编译详解、类加载过程

文章目录Java编译执行过程类加载过程即时编译JITJIT编译优化中的常见技术方法内联逃逸分析 栈上分配 锁消除小总结Java编译执行过程 提到编译,可能大多数人想到的就是将**.java编译成***.class文件,但其实Java代码的编译执行是一个非常复杂的过程,将**.java编译成**.class…

Lesson1:初识编程语言、Python环境搭建

一、什么是编程语言 用来和计算机交流,控制计算机,让计算机按照我们的要求做事情,这样的语言叫做编程语言。 Note:编程语言四个字可以拆成两个部分进行理解——编程语言。 所谓语言,它的作用就是交流,向对…

Redis实战—黑马点评(一) 登录篇

Redis实战 — 黑马点评(一) 登录篇 来自黑马的redis课程的笔记 【黑马程序员Redis入门到实战教程,深度透析redis底层原理redis分布式锁企业解决方案黑马点评实战项目】 目录Redis实战 — 黑马点评(一) 登录篇1. 项目…

深度学习笔记:使用随机梯度下降法识别mnist数据集

深度学习算法实现流程: 1 从训练数据中随机选出一部分数据,称为mini-batch。我们的目标为减小mini-batch损失函数的值 2 计算损失函数关于权重的梯度。梯度方向即为损失函数值减小最快的方向 3 将权重沿梯度下降方向更新 4 重复以上步骤,在…

【自动驾驶汽车技术 | 车载雷达系统】

本文编辑:调皮哥的小助理 1、摘要 自动驾驶汽车传感器系统一般包括4种雷达:激光雷达(Lidar)、毫米波雷达(mmWave Radar)、超声波雷达(Ultrasonic Radar)和红外雷达(Infrared Radar)。目前激光雷达和毫米波雷达是基本和必要的车载传感器设备,…

I.MX6ULL内核开发8:linux设备驱动模型

目录 一、为什么需要设备驱动模型 二、sysfs概述 驱动模型一 驱动模型二 kobject kset kobj_type 一、为什么需要设备驱动模型 早期内核(2.4之前)没有统一的设备驱动模型,但是照样可以使用(之前的led字符设备驱动&#xff…

2023-2-12刷题情况

字母板上的路径 题目描述 我们从一块字母板上的位置 (0, 0) 出发,该坐标对应的字符为 board[0][0]。 在本题里,字母板为board [“abcde”, “fghij”, “klmno”, “pqrst”, “uvwxy”, “z”],如下所示。 我们可以按下面的指令规则行动…

合宙Air103|fbd数据库| fskv - 替代fdb库|LuatOS-SOC接口|官方demo|学习(16):类redis的fbd数据库及fskv库

基础资料 基于Air103开发板:🚗 Air103 - LuatOS 文档 上手:开发上手 - LuatOS 文档 探讨重点 对官方社区库接口类redis的fbd数据库及fskv库的调用及示例进行复现及分析,了解两库的基本原理及操作方法。 软件及工具版本 Luat…