《Java黑皮书基础篇第10版》 第3章【笔记】

第三章

3.1 引言
3.2 boolean数据类型
3.3 单分支if语句

Java 有几种类型的选择语句:单分支 if 语句、双分支if else语句、嵌套 if 语句、多分支 if else 语句、switch 语句和条件表达式

流程图是描述算法或者过程的图 ,处理操作显示在盒子中,棱形的盒子表示一个布尔类型的条件,矩形盒子代表语句

Created with Raphaël 2.3.0 Start 布尔表达式 语句(组) End yes no

布尔表达式应该用括号括住。

if (i > 0) {
	System.out.print("i is positive");
}


如果花括号内只有一条语句,则可以省略花括号。

if (i > 0)
	System.out.print("i is positive");
3.4 双分支if-else语句
Created with Raphaël 2.3.0 Start 布尔表达式 条件为真时执行的语句 End 条件为假时执行的语句 yes no
3.5 嵌套if 语句和多分支 if-else 语句

相比于嵌套if语句,多分支的if-else语句可以避免深度缩进,并使程序易于阅读

Created with Raphaël 2.3.0 Start score >= 90 Grade A End score >= 80 Grade B score >= 70 Grade C score >= 60 Grade D Grade F yes no yes no yes no yes no
3.6 常见的错误和陷阱
常见错误1:对布尔值的冗余测试
//冗余

If (even == true)

​    System.out.print("it is even.");

//这种效果更好

If (even)

​    System.out.print("it is even.");
常见错误 2: 悬空 else 出现的歧义

在同一个块中,else 总是和离它最近的 if 子句匹配。这样,图 a 中的语句就等价于图 b 中的语句。

//错误的缩进
int i = 1, j = 2, k = 3;

if (i > j)
​    if (i > k)
​        System.out.println("A");
else
​        System.out.println("B");

//正确的缩进
int i = 1, j = 2, k = 3;

if (i > j)
​    if (i > k)
​        System.out.println("A");
else
​        System.out.println("B");

由于(i>j)为假,所以图 a 和图 b中的语句不打印任何东西。为强制这个 else 匹配第 一个 if 子句,必须添加一对花括号。

int i = 1, j = 2, k = 3;
if (i > j) {
​    if (i > k)
​        System.out.println("A");
}
else
​        System.out.println("B");
常见错误 3: 两个浮点数值的相等测试

通常,将Epsilon( ϵ \epsilon ϵ)设为 1 0 − 14 10^{-14} 1014来比较两个double 类型的值,而设为 1 0 − 7 10^{-7} 107来比较两个 float 类型的值。

final double EPSILON = 1E-14;
Double x = 1.0 - 0.1 - 0.1 - 0.1 - 0.1 - 0.1
if (Math.abs(x - 0.5) < EPSILON)
​    System.out .println(x " is approximately 0.5" );
常见陷阱 1: 简化布尔变量賦值
if (number % 2 == 0)
​    even = true;
else
​    even = false;

//这样写更好
boolean even = number % 2 ==0;
常见陷阱 2: 避免不同情形中的重复代码
if (inState) { 
​    tuition - 5000;
​    System.out.println("The tuition is " + tuition);
}
     else {
​     System.out.println("The tuition is " + tuition")

//这样写更好
if (instate) {
​    tuition = 5000; 
}
else {
​    tuition = 15000;
}
System.out.println(''The tuirion is " + tuition);
3.7 产生随机数

可以使用Math.random()来产生一个[0.0 , 1.0)之间的随机double值

3.8 示例学习:计算BMI
3.9 示例学习: 计算税率
3.10 逻辑操作符

逻辑操作符!、&&、||、^可以用于产生复合布尔表达式。

p1 != p2 等同于 p1 ^ p2

从教学的角度看,表达式1 <= numberOfDaysInAMonth <= 31是正确的。但是,在Java 中它是错的,因为1 <= numberOfDaysInAMonth得到的是一个布尔值的结果,它是不能和31进行比较的,正确的写法应该是

(1 <= numberOfDaysInAMonth) && (numberOfDaysInAMonth <= 31)

德模佛定理

!(condition1 && condition2)
和
!condition1|| !condition2
是等价的

!(condition1|| condition2)
和
!condition1&&!condition2 
是等价的。

可以简化为等价的表达式:

	! (number % 2 == 0 && number % 3 == 0) 
	(number % 2 != 0 || number % 3 != 0) 

另外一个例子

!(number == 2 || number == 3)
number != 2 && number != 3

在编程术语中,&和||被称为短路或者懒惰操作符,当前一种boolean值可以直接决定计算结果,就不再计算后面的boolean值

3.12 示例学习:彩票
3.13 switch语句
  1. switch表达式必须能计算出一个char、byte、short,int或者String型值,并且必须总是要用括号括住。

  2. value1, …, valueN必须与switch表达式的值具有相同的数据类型。注意: valuel, valueN 都是常量表达式,也就是说这里的表达式是不能包含变量的,不允许出现1+X。

  3. 当switch表达式的值与case语句的值相匹配时,执行从该case开始的语句,直到遇到一个 break语句或到达该 switch 语句的结束。

  4. 默认情况(default)是可选的,当没有一个给出的case与switch表达式匹配时,用来执行该操作。

  5. 关键字 break是可选的。break 语句会立即终止 switch 语句。不要忘记在需要的时候使用break语句。一旦匹配其中一个case,就从匹配的case 处开始执行,直到遇到 break 语句或到达 switch 语句的结束。这种现象称为落空行 为(fall-through behavior)。

3.14 条件表达式

如果布尔表达式的值为 true, 则条件表达式的结果为表达式 expression1; 否则,结果为表达式 expression2。

boolean-expression ? Expression1 : expression2; 
(布尔表达式 ? 表达式1 : 表达式2)

假设希望将 num1 和 num2 中较大的数赋值给max, 可以利用条件表达式,只需编写一 条语句:

max = (num1 > num2) ? Num1 : num2; 

如果num是偶数,下面的语句就显示信息 “num is even";否则显示

“num is odd”:

System.out.println((num % 2 == 0) ? "num is even" : "num is odd");

Java中唯一的三元操作符就是?:两个符号在条件表达式中同时出现

3.15 操作符的优先级和结合规则在这里插入图片描述

如果优先级相同的操作符相邻,则结合规则(associativity) 决定它们的执行顺序。除了赋值操作符之外,所有的二元操作符都是左结合的(left associative)。

a - b + c -d 等价于 ((a - b) + c) - d

a = b+= c = 5 等价于 a = (b += (c = 5))

假设赋值前 a 、b 和 c 都是 1, 在计算表达式之后,a 变成 6,b变成 6, 而 c 变成 5。

3.16 调试

调试是在程序中找到和修改错误的过程

因为编译器可以明确指出错误的位置以及出错的原因,所以语法错误是很容易发现和纠正的。运行时错误也不难找,因为程序在异常终止时,错误的原因和位置都会显示在控制台上。然而,査找**逻辑错误(bug)**就很富有挑战性。

逻辑错误也称为臭虫(bug)。査找和改正错误的过程称为调试(debugging)。

调试的一般途径是采用各种方法逐步缩小程序中 bug 所在的范围。可以手工跟踪(hand trace) 程序 ( 即通过读程序找错误 ),也可以插入打印语句,显示变量的值或程序的执行流程。

以上方法适用于短小、简单的程序。对于庞大、复杂的程序,最有效的调试方法还是使用调试工具。

JDK包含了一个命令行调试器jdb,运行自身的一个 Java 解释器的拷贝。

一次执行一条语句

跟踪进入或者一步运行过一个方法

设置断点

显示变量

显示调用堆栈

修改变量

### 回答1: 11.6题要求我们实现一个简单的Java虚拟机,可以执行一些简单的Java程序。具体来说,我们需要实现以下几个部分: 1. 读取Java字节码文件,将其解析成指令序列。 2. 实现一个虚拟机栈,用于存储局部变量和操作数栈。 3. 实现指令集,包括常量加载、算术运算、比较运算、跳转等指令。 4. 执行指令序列,模拟Java程序的执行过程。 在实现过程中,我们需要注意一些细节问题,比如指令的操作数类型、栈帧的管理、异常处理等。此外,我们还需要考虑性能问题,比如如何优化指令的执行速度、如何减少内存占用等。 总之,实现一个Java虚拟机是一项非常复杂的任务,需要深入理解Java语言和计算机系统的原理。但是,通过这个练习,我们可以更好地理解Java程序的执行过程,提高我们的编程能力。 ### 回答2: Java黑皮第1111.6主要探讨了Java中的异常处理机制,以及如何自定义异常。本节的核心知识点包括: 1. 异常的概念:异常是在程序执行期间发生的错误或其他意外情况,它打断了正常的程序执行流程。 2. 异常的分类:Java中将异常分为Checked异常和Unchecked异常。Checked异常在编译期间就必须捕获处理,否则编译器会提示错误。Unchecked异常则不需要在编译期间捕获,但程序在运行时会抛出异常。 3. 异常处理机制:Java提供了try-catch语句用于捕获和处理异常。try块中放置可能会抛出异常的代码,catch块中处理异常的代码。 4. 自定义异常:Java允许我们自定义异常类,继承自Exception或RuntimeException,也可以添加自己的字段、方法等。 这一节的课后题主要是通过代码实践来加深对异常处理机制的理解,以及练习自定义异常类。有一道比较经典的题目是编写一个自定义异常类,并在程序中抛出这个异常。这个题目的思路可以参考以下步骤: 1. 创建一个自定义异常类,继承自Exception或RuntimeException。 2. 在构造方法中传入异常信息,然后调用父类的构造方法。 3. 在程序的某个地方,使用throw关键字抛出自定义异常。 4. 在主程序中使用try-catch语句捕获自定义异常,在catch块中处理异常。 例如,我们可以创建一个自定义异常类MyException,并在程序的某个地方抛出这个异常: class MyException extends RuntimeException{ public MyException(String message){ super(message); } } public class Main{ public static void main(String[] args){ try{ throw new MyException("这是一个自定义异常"); }catch(MyException e){ System.out.println("捕获到自定义异常:" + e.getMessage()); } } } 在这个例子中,我们创建了一个自定义异常类MyException,它继承自RuntimeException。在程序的try块中,我们使用throw关键字抛出这个异常。在主程序中,我们使用try-catch语句捕获这个自定义异常,并在catch块中处理异常并输出异常信息。 总的来说,Java黑皮第1111.6是一个非常重要的节,掌握异常处理机制和自定义异常类的知识对于Java程序开发至关重要。在实际的开发中,我们需要根据实际情况进行异常处理,使程序更加健壮和可靠。 ### 回答3: 11.6题是要求实现一个基于协程(Coroutine)的简单HTTP服务器。协程是一种比线程更轻量级的并发机制,可以在单个线程中实现多个协程的交替执行,类似于CPU在操作系统中的任务切换。HTTP服务器是指接受HTTP请求并返回HTTP响应的程序或服务。 在实现基于协程的HTTP服务器时,我们需要使用Java的协程库,比如Quasar,ByteBuddy或Kilim。在这个服务器中,每个HTTP请求都被视为一个协程,并且服务器需要实现以下功能: 1. 监听并接受HTTP请求:服务器需要启动一个监听端口,以接受客户端的HTTP请求,并将其转变为协程来处理。 2. 解析HTTP请求:对于每个接受的HTTP请求,服务器需要解析其请求头和主体,以确定请求类型、请求路径、请求方法等信息。 3. 处理HTTP请求:服务器需要根据请求的类型和路径,决定如何处理每个HTTP请求。常见的处理方式是返回文件内容、执行代码、跳转到其它页面等。在协程处理HTTP请求时,服务器可以暂停当前协程,等待文件读取、代码执行等耗时操作完成后,再恢复当前协程继续执行。 4. 返回HTTP响应:服务器需要将处理结果封装成HTTP响应,包括响应头和响应主体内容,并将其发送回客户端。 在实现这个服务器时,需要注意以下几点: 1. Java协程库的选择:Java提供了不同的协程库,每个库有不同的优缺点。要根据实际需求选择适合的协程库,并掌握其基本使用方法。 2. HTTP请求的解析:需要熟悉HTTP协议的请求格式和规范,以正确解析每个请求,并提取需要的信息。 3. 耗时操作的处理:在处理HTTP请求时,可能会遇到需要,等待文件读取、代码执行等耗时操作。要注意在这些操作上暂停当前协程,并在操作完成后恢复协程的执行。 4. 程序的安全性:在实现HTTP服务器时,要注意相关的安全问题,比如防止跨站脚本(XSS)攻击、拒绝服务(DOS)攻击、SQL注入等。 总之,基于协程实现HTTP服务器是一项复杂的工作,需要综合掌握HTTP协议、Java协程库、耗时操作处理、程序安全等多个方面的知识。如果熟练掌握这些技能,就可以实现高效、安全、稳定的HTTP服务器,满足不同场景下的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值