Java标准异常

Throwable这个Java类被用来表示任何可以作为异常被抛出的类。Throwable对象 可分为两种类型(指从Throwable继承而得到的类型): Error用来表示编译时和系统错误(除特殊情况外,一般不用你关心) ; Exception是 可以被抛出的基本类型,在Java类库、用户方法以及运行时故障中都可能拋出Exception型异常。所以Java程序员关心的基类型通常是Exception。

要想对异常有全面的了解,最好去浏览一下HTML格式的Java文档( 可以从java.sun.com下载)。为了对不同的异常有个感性的认识,这么做是值得的。但很快你就会发现,这些异常除了名称外其实都差不多。同时,Java中异常的数目在持续增加,所以在书中简单罗列它们毫无意义。所使用的第三方类库也可能会有自己的异常。对异常来说,关键是理解概念以及如何使用。

异常的基本的概念是用名称代表发生的问题,并且异常的名称应该可以望文知意。异常并非全是在java.lang包里定义的;有些异常是用来支持其他像util、net和io这样的程序包,这些异常可以通过它们的完整名称或者从它们的父类中看出端倪。比如,所有的输入/输出异常都是从java.io.IOException继承而来的。

一个特殊的例子:RuntimeException

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

      如果必须对传递给方法的每个引用都检查其是否为null (因为无法确定调用者是否传入了非法引用),这听起来着实吓人。幸运的是,这不必由你亲自来做,它属于Java的标准运行时检测的一部分。如果对null引用进行调用,Java会 自动抛出NullPointerException异常,所以上述代码是多余的,尽管你也许想要执行其他的检查以确保NullPointerException不会出现。

属于运行时异常的类型有很多,它们会自动被Java虚拟机抛出,所以不必在异常说明中把它们列出来。这些异常都是从RuntimeException类继承而来,所以既体现了继承的优点,使用起来也很方便。这构成了一组具有相同特征和行为的异常类型。并且,也不再需要在异常说明中声明方法将拋出RuntimeException类型的异常(或者任何从RuntimeException继承的异常),它们也被称为“不受检查异常”。这种异常属于错误,将被自动捕获,就不用你亲自动手了。要是自己去检查RuntimeException的话,代码就显得太混乱了。不过尽管通常不用捕获RuntimeException异常,但还是可以在代码中抛出RuntimeException类型的异常。

如果不捕获这种类型的异常会发生什么事呢?因为编译器没有在这个问题上对异常说明进行强制检查,RuntimeException类 型的异常也许会穿越所有的执行路径直达main方法,而不会被捕获。要明白到底发生了什么,可以试试下面的例子:

class NeverCaught{static void f() {throw new RuntimeException();}static void g() {f();}public static void main() {g();}
}


      可能读者已经发现,RuntimeException (或任何从它继承的异常)是-一个特例。对于这种异常类型,编译器不需要异常说明,其输出被报告给了System.err:

Exception in thread "main" java.lang.RuntimeException
   at throwException.NeverCaught.f(Text.java:16)
   at throwException.NeverCaught.g(Text.java:19)
   at throwException.NeverCaught.main(Text.java:22)

所以答案是:如果RuntimeException没 有被捕获而直达main(),那么在程序退出前将调用异常的printStackTrace0方法。

请务必记住:只能在代码中忽略RuntimeException (及其子类)类型的异常,其他类型异常的处理都是由编译器强制实施的。究其原因,RuntimeException代表的是编程错误:

1)无法预料的错误。比如从你控制范围之外传递进来的null引用。

2)作为程序员,应该在代码中进行检查的错误。( 比如对于ArrayIndexOutOf-BoundsException,就得注意一下数组的大小了。) 在一一个地方发生的异常,常常会在另一个地方导致错误。

你会发现在这些情况下使用异常很有好处,它们能给调试带来便利。

值得注意的是:不应把Java的异常处理机制当成是单一用途的工具。 是的,它被设计用来处理一些烦人的运行时错误,这些错误往往是由代码控制能力之外的因素导致的;然而,它对于发现某些编译器无法检测到的编程错误,也是非常重要的。

使用finally进行清理

对于一些代码,可能会希望无论try块中的异常是否抛出,它们都能得到执行。这通常适用于内存回收之外的情况(因为回收由垃圾回收器完成)。为了达到这个效果,可以在异常处理程序后面加上finally子句。为了证明finally总能运行,可以试试下面这个程序
public class FinallyWorks {static int count=0;public static void main(String[] args) {while(true) {try {if(count++==0) {throw new Exception();}System.out.println("No Exception");}catch(Exception e) {System.out.println("Exception");}finally {System.out.println("In finally");if(count==3) break;}}}
}


      可以从输出中发现,无论异常是否被抛出,finally子句总能被执行。

这个程序也给了我们一些思路,当Java中的异 常不允许我们回到异常抛出的地点时,那么该如何应对呢?如果把try块放在循环里,就建立了一个“程序继续执行之前必须要达到”的条件。还可以加入一个static类型的计数器或者别的装置,使循环在放弃以前能尝试-定的次数。这将使程序的健壮性更上一个台阶。

finally用 来做什么
      对于没有垃圾回收和析构函数自动调用机制的语言来说,finally非常 重要。它能使程序员保证:无论try块里发生了什么,内存总能得到释放。但Java有 垃圾回收机制,所以内存释放不再是问题。而且,Java也没有析构函数可供调用。那么,Java在什么情况下才能用到finally呢?

当要把除内存之外的资源恢复到它们的初始状态时,就要用到finally子句。这种需要清理的资源包括:已经打开的文件或网络连接,在屏幕上画的图形,甚至可以是外部世界的某个开关,而且在异常没有被当前处理程序捕获的情况下,异常处理机制也会也会跳到更高一层的异常处理程序之前,执行finally子句。最后当涉及break和continue语句的时候,finally 子句也会得到执行。请注意,如果把finally子句和带标签的break及continue配合使用,在Java里就没必要使用goto语句了。


return中使用finally语句
因为finally语句总会执行,所以在一个方法当中,可以多个点返回,并且保证重要的清理工作仍然可以执行
public class Text {public static void f(int i) {try {if(i==1) return;if(i==2) return;if(i==3) return;if(i==4) return;return;}finally {System.out.println("Clean");}}public static void main(String[] args) {for(int i=1;i<5;i++) {f(i);}}
}输出:CleanCleanCleanClean

从输出可以看出,在finally类内部,从何处返回无关紧要

缺憾:异常丢失

遗憾的是,异常处理程序也有瑕疵。异常作为程序出错的标志,绝不应该被忽略,但是它还是可能被轻易忽略。用某些特殊的方式使用finally子句,就会发生这种情况:
public class LostMessage {void f() throws NoSuchFieldException {throw new NoSuchFieldException("VeryImportant");}void dispose() throws NullPointerException {throw new NullPointerException("A trivial exception");}public static void main(String[] args) {try {LostMessage lm = new LostMessage();try {lm.f();} finally {lm.dispose();//会取代f()中的异常,这是异常丢失
            }} catch (Exception e) {System.out.println(e);}//一种更简单的异常丢失,在这里即使抛出的异常,也不会产生任何输出try {throw new RuntimeException();}finally {return;}}
}


      从输出中可以看到,NoSuchFieldException不见了 ,它被finally子 句里的NullPointerException所取代。这是相当严重的缺陷,因为异常可能会以一种比前面例子所示更微妙和难以察觉的方式完全丢失。相比之下,C++把“前一个异常还没处理就抛出下一个异常”的情形看成是糟糕的编程错误。也许在Java的未来版本中会修正这个问题(另一方面,要把所有抛出异常的方法,如上例中的dispose0方法,全部打包放到try catch子句里面)。

异常限制

当覆盖方法的时候,只能抛出从基类方法中异常说明列出的异常。这个限制很有用,因为这意味着,当基类使用的代码应用到其派生类对象的时候,一样能够工作,异常也不例外。

构造器


      有- -点很重要, 即你要时刻询问自己“如果异常发生了 ,所有东西能被正确的清理吗? ”尽管大多数情况下是非常安全的,但涉及构造器时,问题就出现了。构造器会把对象设置成安全的初始状态,但还会有别的动作,比如打开一个文件, 这样的动作只有在对象使用完毕并且用户调用了特殊的清理方法之后才能得以清理。如果在构造器内抛出了异常,这些清理行为也许就不能正常工作了。这意味着在编写构造器时要格外细心。

读者也许会认为使用finally就可以解决问题。但问题并非如此简单,因为finally会 每次都执


行清理代码。如果构造器在其执行过程中半途而废,也许该对象的某些部分还没有被成功创建,而这些部分在finally子句中却是要被清理的。

在下面的例子中,建立了一个InputFile类,它能打开-一个文件并且每次读取其中的一行。这里使用了Java标准输入/输出库中的FileReader和BufferedReader类(将在第18章讨论),这些类的基本用法很简单,读者应该很容易明白:

public class InputFile {private BufferedReader in;public InputFile(String fname) throws Exception {try {in = new BufferedReader(new FileReader(fname));} catch (FileNotFoundException e) {System.out.println("can not open" + fname);throw e;} catch (Exception e) {try {in.close();} catch (IOException e2) {System.out.println("in.close unseccessful");}throw e;} finally {}}public String getLine() {String s;try {s = in.readLine();} catch (IOException e) {throw new RuntimeException("readLine failed");}return s;}public void dispose() {try {in.close();System.out.println("dispose successful");} catch (IOException e2) {throw new RuntimeException("in.close failed");}}public static void main(String[] args) throws Exception {InputFile p=new InputFile("FinallyWorks.java");}
}


      InputFile的构造器接受字符串作为参数,该字符串表示所要打开的文件名。在try块中,会使用此文件名建立了FileReader对象。FileReader对象本身用处并不大,但可以用它来建立BufferedReader对象。注意,使用InputFile的好处就能是把两步操作合而为一。

如果FileReader的构造器失败了,将拋出FileNotFoundException异常。 对于这个异常,并不需要关闭文件,因为这个文件还没有被打开。而任何其他捕获异常的catch子句必须关闭文件,因为在它们捕获到异常之时,文件已经打开了(当然,如果还有其他方法能抛出FileNotFoundException,这个方法就显得有些投机取巧了。这时,通常必须把这些方法分别放到各自的try块里)。close0方法也可能会抛出异常,所以尽管它已经在另一个Catch子句块里了,


还是要再用一层try-catch-对Java编译 器而言,这只不过是又多了一对花括号。在本地做完处理之后,异常被重新抛出,对于构造器而言这么做是很合适的,因为你总不希望去误导调用方,让他认为“这个对象已经创建完毕,可以使用了”。

在本例中,由于finally会在每次完成构造器之后都执行一遍,因此它实在不该是调用close0关闭文件的地方。我们希望文件在InputFile对象的整个生命周期内都处于打开状态。

getLine0方法会返回表示文件下- -行内容的字符串。它调用了能抛出异常的readLine(,但是这个异常已经在方法内得到处理,因此getLineO不会抛出任何异常。在设计异常时有一个问题:应该把异常全部放在这层处理 ;还是先处理一 部分,然后再向 上层抛出相同的 (或新的)异常;又或者是不做任何处理直接向上层抛出。如果用法恰当的话,直接向上层抛出的确能简化编程。在这里,getLineO方 法将异常转换为RuntimeException,表示-一个编程错误。

用户在不再需要InputFile对象时,就必须调用dispose(0方法,这将释放BuferedReader和/或FileReader对象所占用的系统资源(比如文件句柄),在使用完InputFile对象之前是不会调用它的。可能你会考虑把上述功能放到finalizeO里面,但我在第5章讲过,你不知道finalize()会不会被调用(即使能确定它将被调用,也不知道在什么时候调用)。这也是Java的缺陷:除了内存的清理之外,所有的清理都不会自动发生。所以必须告诉客户端程序员,这是他们的责任。

对于在构造阶段可能会抛出异常,并且要求清理的类,最安全的使用方式是使用嵌套的try子句:

public class Cleanup {public static void main(String[]  args) {try {InputFile  in =new InputFile("Cleanup.java");try {String s;int i=1;while((s=in.getLine())!=null) {;}}catch(Exception e) {System.out.println("Caught Exception in main");e.printStackTrace(System.out);}finally {in.dispose();}}catch(Exception e) {System.out.println("InputFile construction failed");}}
}


      请仔细观察这里的逻辑:对InputFile对象的构造在其自己的try语句块中有效,如果构造失败,将进入外部的catch子句,而dispose0方法不会被调用。但是,如果构造成功,我们肯定想确保对象能够被清理,因此在构造之后立即创建了一个新的try语句块。执行清理的finally与内部的try语句块相关联。在这种方式中,finally子 句在构造失败时是不会执行的,而在构成成功时将总是执行。

这种通用的清理惯用法在构造器不抛出任何异常时也应该运用,其基本规则是:在创建需要清理的对象之后,立即进入一个try-finally语句块:

class NeedsCleanup {private static long counter = 1;private final long id = counter++;public void dispose() {System.out.println("NeedsCleanup " + id + " dispose");}
}class ConstructionsException extends Exception {
}class NeedsCleanup2 extends NeedsCleanup {public NeedsCleanup2() throws ConstructionsException {}
}public class CleanupIdiom {public static void main(String[] args) {NeedsCleanup nc1=new NeedsCleanup();try {}finally {nc1.dispose();}NeedsCleanup nc2=new NeedsCleanup();NeedsCleanup nc3=new NeedsCleanup();try {}finally {nc2.dispose();nc3.dispose();}try {NeedsCleanup2 nc4=new NeedsCleanup2();try {NeedsCleanup2 nc5=new NeedsCleanup2();try {}finally {nc5.dispose();}}catch(ConstructionsException e) {System.out.println(e);}finally {nc4.dispose();}}catch(ConstructionsException e) {System.out.println(e);}}
}


      在main方法中,Section 1相当简单:遵循了在可去除对象之后紧跟try-finally的原则。如果对象构造不能失败,就不需要任何catch。在Section 2中,为了构造和清理,可以看到具有不能失败的构造器的对象可以群组在一起。

Section 3展示了如何处理那些具有可以失败的构造器,且需要清理的对象。为了正确处理这种情况,事情变得很棘手,因为对于每一一个构造, 都必须包含在其自己的try-finally语句块中,并且每一个对象构造必须都跟随一个try-finally语 句块以确保清理。

本例中的异常处理的棘手程度,对于应该创建不能失败的构造器是一个有力的论据,尽管这么做并非总是可行。

异常匹配

class A extends Exception{}
class B extends A{}
//异常匹配
public class Human {public static void main(String[] args) {try {throw new B();}catch(B s) {System.out.println("caught B");}catch(A a) {System.out.println("caught A");}//匹配基类try {throw new B();}catch(A a) {System.out.println("caught A");}}
}


      Sneeze异常会被第一个匹配的catch子句捕获,也就是程序里的第一个。然而如果将这个catch子句删掉,只留下Annoyance的catch子句,该程序仍然能运行,因为这次捕获的是Sneeze的基类。换句话说,catch(Annoyance e)会捕获Annoyance以及所有从它派生的异常。这一点非常有用,因为如果决定在方法里加上更多派生异常的话,只要客户程序员捕获的是基类异常,那么它们的代码就无需更改。

如果把捕获基类的catch子句放在最前面,以此想把派生类的异常全给“屏蔽”掉,就像这样:
  

try {throw new B();}catch(A s) {System.out.println("caught B");}catch(B a) {System.out.println("caught A");}

这样编译器就会发现,B的catch语句永远不会执行,因此他会向你报告错误

其他可选方式


      异常处理系统就像-一个活门 (trap door),使你能放弃程序的正常执行序列。当“异常情形”发生的时候,正常的执行已变得不可能或者不需要了,这时就要用到这个“活门”。异常代表了当前方法不能继续执行的情形。开发异常处理系统的原因是,如果为每个方法所有可能发生的错误都进行处理的话,任务就显得过于繁重了,程序员也不愿意这么做。结果常常是将错误忽略。应该注意到,开发异常处理的初衷是为了方便程序员处理错误。

异常处理的一个重要原则是“只有在你知道如何处理的情况下才捕获异常”。实际上,异常处理的一个重要目标就是把错误处理的代码同错误发生的地点相分离。这使你能在-段代码中专注于要完成的事情,至于如何处理错误,则放在另一段代码中完成。这样以来,主干代码就不会与错误处理逻辑混在一起, 也更容易理解和维护。通过允许-一个处理程序去处理多个出错点,异常处理还使得错误处理代码的数量趋向于减少。

“被检查的异常”使这个问题变得有些复杂,因为它们强制你在可能还没准备好处理错误的时候被迫加上catch子句,这就导致了吞食则有害(harmful if swallowed)的问题:

 try {

      11... to do something useful

      } catch(obligatoryException e) {} 1 Gulp!

程序员们只做最简单的事情(包括我自己,在本书第1版中也有这个问题),常常是无意中“吞食”了异常;然而一旦这么做,虽然能通过编译,但除非你记得复查并改正代码,否则异常将会丢失。异常确实发生了,但“吞食”后它却完全消失了。因为编译器强迫你立刻写代码来处理异常,所以这种看起来最简单的方法,却可能是最糟糕的做法。


      当我意识到犯了这么大一个错误时,简直吓了一大跳。在本书第2版中,我在处理程字里通过打印栈轨迹的方法“修补”了这个问题(本章中的很多例子还是使用了这种方法,看起来还是比较合适的)。虽然这样可以跟踪异常的行为,但是仍旧不知道该如何处理异常。这一节,我们来研究下“被检查的异常”及其并发症,以及采用什么方法来解决这些问题。

这个话题看起来简单,但实际上它不仅复杂,更重要的是还非常多变。总有人会顽固地坚持自己的立场,声称正确答案( 也是他们的答案)是显而易见的。我觉得之所以会有这种观点,是因为我们使用的工具已经不是ANSI标准出台前的像C那样的弱类型语言,而是像C++和Java这样的“强静态类型语言”(也就是编译时就做类型检查的语言),这是前者所无法比拟的。当刚开始这种转变的时候(就像我-样),会觉得它带来的好处是那样明显,好像类型检查总能解决


      所有的问题。在此,我想结合我自己的认识过程,告诉读者我是怎样从对类型检查的绝对迷信变成持怀疑态度的;当然,很多时候它还是非常有用的,但是当它挡住我们的去路并成为障碍的时候,我们就得跨过去。只是这条界限往往并不是很清晰(我最喜欢的一句格言是:所有模型都是错误的,但有些是能用的)。12.12.1 历史

异常处理起源于PL/1和Mesa之类的系统中,后来又出现在CLU、Smalltalk、 Modula-3、 Ada、Eiffel、C++、 Python、 Java以及 后Java语言Ruby和C#中。Java的设计和C++很相似,只是Java的设计者去掉了一些他们认为C++设计得不好的东西。

为了能向程序员提供一个 他们更愿意使用的错误处理和恢复的框架,异常处理机制很晚才被加入C++标准化过程中,这是由C+ +的设计者Bjarne Stroustrup所倡议的。C++的异常模型主要借鉴了CLU的做法。然而,当时其他语言已经支持异常处理了:包括Ada、Smalltalk (两者都有异常处理,但是都没有异常说明),以及Modula-3 (它既有异常处理也有异常说明)。

Liskov和Snyder在他们的一篇讨论该主题的独创性论文e中指出,用瞬时风格(transientfashion)报告错误的语言(如C中)有一个主要缺陷,那就是:

.....每次调用的时候都必须执行条件测试,以确定会产生何种结果。这使程序难以阅读,并且有可能降低运行效率,因此程序员们既不愿意指出,也不愿意处理异常。”

因此,异常处理的初衷是要消除这种限制,但是我们又从Java的“ 被检查的异常”中看到了这种代码。他们继续写道:

异常使用指南


应该在下列情况下使用异常:

1)在恰当的级别处理问题。(在知道该如何处理的情况下才捕获异常。)2)解决问题并且重新调用产生异常的方法。

3)进行少许修补,然后绕过异常发生的地方继续执行。4)用别的数据进行计算,以代替方法预计会返回的值。

5)把当前运行环境下能做的事情尽量做完,然后把相同的异常重抛到更高层。6)把当前运行环境下能做的事情尽量做完,然后把不同的异常抛到更高层。7)终止程序。

8)进行简化。(如果你的异常模式使问题变得太复杂,那用起来会非常痛苦也很烦人。)

9)让类库和程序更安全。(这既是在为调试做短期投资,也是在为程序的健壮性做长期投资.)

总结

异常处理的优点之-就是它使得你可以在某处集中精力处理你要解决的问题,而在另一处处理你编写的这段代码中产生的错误。尽管异常通常被认为是一种工具,使得你可以在运行时报告错误并从错误中恢复,但是我-直怀疑到 底有多少时候“恢复”真正得以实现了, 或者能够得以实现。我认为这种情况少于10%,并且即便是这10%,也只是将栈展开到某个已知的稳定状态,而并没有实际执行任何种类的恢复性行为。无论这是否正确,我一直相信“报告”功能是异常的精髓所在。Java坚定地强调将所有的错误都以异常形式报告的这一事实,正是它远远超过诸如C++这类语言的长处之一一,因为在C++这类语言中,需要以大量不同的方式来报告错误,或者根本就没有提供错误报告功能。- 致的错误报告系统意味着,你再也不必对所写的每一- 段代码,都质问自己“ 错误是否正在成为漏网之鱼?”(只要你没有“吞咽”异常,这是关键所在! )。

就像你将要在后续章节中看到的,通过将这个问题甩给其他代码一即使你是通过抛出RuntimeException来实现这-点的一 你在设计和实现时, 便可以 专注于更加有趣和富有挑战性的问题了。

转载于:https://www.cnblogs.com/QianYue111/p/10349353.html

通过异常处理错误-2相关推荐

  1. 统一异常处理+错误编码设计方案

    统一异常处理+错误编码设计方案 参考文章: (1)统一异常处理+错误编码设计方案 (2)https://www.cnblogs.com/wd326150354/p/10861713.html 备忘一下 ...

  2. java中使用什么来做错误处理_JAVA基础--如何通过异常处理错误

    <Thinking in Java>上对这章的讲解不少,可见重要性,学习和总结一些主要的记录下来. 一.创建自定义异常 package Exception; class SimpleExc ...

  3. java通过异常处理错误_java 通过异常处理错误

    1.java异常标准 在java中,Throwable这个类是所有异常或错误的父类.Throwable可以分为两种类型: error:表示编译时和系统错误,除特殊情况外,一般不用担心 exceptio ...

  4. 异常处理—错误抛出机制

    错误抛出机制:   把可能出现异常的代码写在try{}里,使用catch(){}设置一些异常陷阱来捕获异常.例如: 没有异常处理时异常的抛出机制:   为什么出现异常会在控制台上显示打印红色的异常呢? ...

  5. thinking-in-java(12)通过异常处理错误

    [12.0]开场白 1)java的基本理念:结构不佳的代码不能运行: 2)改进的错误恢复机制:是提供代码健壮性的最强有力的方式: 3)java异常: 3.1)java采用异常来提供一致的错误报告模型, ...

  6. RAD Studio C++ Builder10.4 补丁Patch 2仍然没有彻底解决C ++ Android异常处理错误

    昨天发布的10.4 Patch#2,对DelphiLSP代码完成进行了许多调整和更改 Delphi 10.4重新设计了Code Insight,这是Delphi IDE十年来最重大的变化之一.现在,它 ...

  7. 通过异常处理错误(6):异常匹配、其他

    一.异常匹配 抛出异常的时候,异常处理系统会按照代码的书写顺序找出"最近"的处理程序.找到匹配的处理程序之后,它就认为异常将得到处理,然后就不再继续查找. 查找的时候并不要求抛出的 ...

  8. java通过异常处理错误,java基础之通过错误处理异常

    我们在编程过程中,通常需要时刻关注可能遇到的问题,此时可以把问题分为两类:普通问题与异常问题.普通问题:我们可以通过从当前环境中获取到的信息来解决这个问题:而异常问题:在当前环境中获取到的信息并不能解 ...

  9. PHP错误和异常处理

    [TOC] PHP错误和异常处理 PHP的错误和异常是两个概念PHP的错误处理:1.语法错误2.环境错误3.逻辑错误PHP的异常类型: PHP7的错误和异常 PHP 7 改变了大多数错误的报告方式. ...

最新文章

  1. ABP入门系列(7)——分页实现
  2. [UVa10296]Jogging Trails
  3. 学计算机的管理医生,计算机科学与技术系医学生管理工作体会.pdf
  4. GPU Pro2 - 1.Terrain and Ocean Rendering with Hardware Tessellation
  5. 3dmax标注尺寸插件_抖音最火CAD插件教程汇总
  6. python怎么加载库_Python库如何安装和导入
  7. c#中用声音提示报警
  8. 易语言linux静态编译失败,易语言静态编译连接失败
  9. 细聊智能家居开发中必备的通信协议
  10. 学习笔记16-HC05
  11. 音视频编解码基础知识
  12. 解决哈希冲突的方法,Hash的介绍,散列因子的介绍
  13. 计算机科学与技术研究机构名称,计算机科学与技术学院研究生团队获得SemEval-2021国际语义评测比赛Task 5第一名...
  14. 【USACO】山峰暸望
  15. uva10635 Prince and Princess
  16. Broadcast 和 BroadcastReceiver
  17. 高博SLAM14讲ceres实战问题调试记录
  18. 〖NOIP2004P〗FBI树
  19. 旅行商问题回溯法求解
  20. 淘宝村峰会 | 对话:农村电商让老百姓有尊严地脱贫

热门文章

  1. 与孩子一起学编程python_与孩子一起学编程(Python读书笔记3)
  2. vscode 暂停运行_用VS Code开发STM32(三)——调试
  3. 一元线性回归多元线性回归
  4. 2021年最想学习的五大编程语言
  5. JavaScript对数组的常见操作
  6. C++ vector越界的问题
  7. 一年级学python_你是如何自学 Python 的?
  8. 启动之后自己关闭_如何关闭Mac开机总是要输入密码?
  9. 两车相撞的力怎么计算_两车都向中间并线时相撞 算谁的责任
  10. C语言学习笔记---指针