引言
- 程序可以基于条件决定执行哪些语句
boolean 数据类型
- boolean数据类型声明一个具有值true或者false的变量
- Java提供六种关系操作符(relational operator)(也称为比较操作符(comparison operator))
Java操作符 | 数学符号 | 名称 | 示例(半径为5) | 结果 |
---|---|---|---|---|
< | < | 小于 | radius < 0 | false |
<= | ≤ | 小于等于 | radius <= 0 | false |
> | > | 大于 | radius > 0 | true |
>= | ≥ | 大于等于 | radius >= 0 | true |
== | = | 等于 | radius == 0 | false |
!= | ≠ | 不等于 | radius != 0 | true |
- 相等的关系操作符是两个等号(==),而不是一个等号(=),后者是指赋值操作符。
- 保存布尔值的变量称为布尔变量(boolean variable)
程序清单 3-1 AdditionQuiz.java
import java.util.Scanner;
public class AdditionQuiz {
public static void main(String[] args) {
int number1 = (int) (System.currentTimeMillis() % 10);
int number2 = (int) (System.currentTimeMillis() / 10 % 10);
//Create a Scanner
Scanner input = new Scanner(System.in);
System.out.print(
"What is " + number1 + " + " + number2 + " ? ");
int answer = input.nextInt();
System.out.println(number1 + " + " + number2 + " = " + answer + " is " +
(number1 + number2 == answer));
}
}
if语句
- if语句是一个构造,允许程序确定执行的可选路径
- 单分支if语句
- 是指当且仅当条件为true时执行一个动作,其语法如下
if(布尔表达式){
语句(组);
}
- 是指当且仅当条件为true时执行一个动作,其语法如下
- 流程图是描述算法或者过程的图,以各种盒子显示步骤,并且通过箭头连接它们给出顺序。处理操作显示在这些盒子中,连接它们的箭头代表控制流程。棱形的盒子表示一个布尔类型的条件,矩形盒子代表语句。
- 省略括号可以让代码更加简短,但是容易产生错误。当你返回去修改略去括号的代码的时候,容易忘记加上括号
程序清单 3-2 SimpleIfDemo.java
import java.util.Scanner;
public class SimpleIfDemo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter an integer: ");
int number = input.nextInt();
if (number % 5 == 0)
System.out.println("HiFive");
if (number % 2 == 0)
System.out.println("HiEven");
}
}
双分支if - else语句
- if - else 语句根据条件是真或者是假,决定执行的路径
if(布尔表达式){
布尔表达式为真时执行的语句(组);
}
else{
布尔表达式为假时执行的语句(组);
}
嵌套的if语句和多分支if - else 语句
- if 语句可以在另外一个if语句中,形成嵌套的if语句
常见错误和陷阱
- 忘记必要的括号,在错误的地方结束if语句,将
==
错当作=
来使用,悬空else分支,是选择语句中常见的错误。if - else语句中重复的语句,以及测试双精度值的相等是常见的陷阱。 - 常见错误:
- 忘记必要的括号
//错误的
if(radius >= 0)
area = radius * radius * PI;
System.out.println("The area " + " is " + area);
//正确的
if(radius >= 0){
area = radius * radius * PI;
System.out.println("The area " + " is " + area);
}
//错误的等价于
if(radius >= 0)
area = radius * radius * PI;
System.out.println("The area " + " is " + area);
- 忘记必要的括号
- 错误地在if行出现分号
//逻辑错误
if(radius >= 0);//error
{
area = radius * radius * PI;
System.out.println("The area " + " is " + area);
}
//等价于
if(radius >= 0){ };//error 空的块
{
area = radius * radius * PI;
System.out.println("The area " + " is " + area);
}
- 对布尔值的冗余测试
if (even == true)
System.out.println("It is even");
//等价于 这种更好
if(even)
System.out.println("It is even");
- 悬空else出现的歧义 ```java //看缩进的话是else与第一个if匹配,但实际上是else和第二个else匹配 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”);
- 两个浮点数值的相等测试
- 浮点数具有有限的计算精度;涉及浮点数的计算可能引入舍入错误。因此,两个浮点数值的相等测试并不可靠
```java
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);
- 常见陷阱:
- 简化布尔变量赋值
if(number % 2 == 0)
even = true;
else
even = false;
//等价于
boolean even
= number % 2 == 0;
- 简化布尔变量赋值
- 避免不同情形中的重复代码
//代码冗余
if(inState){
tuition = 5000;
System.out.println("The tuition is " + tuition);
}
else{
tuition = 15000;
System.out.println("The tuition is " + tuition);
}
//等价于
if(inState){
tuition = 5000;
}
else{
tuition = 15000;
}
System.out.println("The tuition is " + tuition);
产生随机数
- 你可以使用
Math.random()
来获得一个0.0到1.0之间的随机double值,不包括1.0
程序清单 3-3 SubtractionQuiz.java
import java.util.Scanner;
public class SubtractionQuiz {
public static void main(String[] args) {
// 1.Generate two random single-digit integers
int number1 = (int) (Math.random() * 10);
int number2 = (int) (Math.random() * 10);
//2. If number1 <number2,swap number1 with number2
if (number1 < number2) {
int temp = number1;
number1 = number2;
number2 = temp;
}
//3. Prompt the student to answer "What is number1 - number2?"
System.out.print("What is " + number1 + " - " + number2 + " ? ");
Scanner input = new Scanner(System.in);
int answer = input.nextInt();
//4.Grade the answer and display the result
if (number1 - number1 == answer)
System.out.println("You are correct!");
else {
System.out.println("Your answer is wrong.");
System.out.println(number1 + " - " + number2 +
" should be " + (number1 - number2));
}
}
}
a.产生一个随机整数i,使得0<= i < 20?
b.产生一个随机整数i,使得10<= i < 20?
c.产生一个随机整数i,使得0<= i <= 50?
d.编写一个表达式,随机返回0或者1。
import java.util.Random;
public class sa {
public static void main(String[] args) {
Random random = new Random();
for (int i = 0; i < 100; i++) {
System.out.println((int)(random.nextDouble()*20));//a
System.out.println((int)(random.nextDouble()*10 + 10));//b
System.out.println((int)(random.nextDouble()*+ 51));//c
System.out.println(random.nextBoolean()?1:0);//d
/*分析
a.因为取不到1.0的值,要求0<= i < 20,只需 * 20即可
b.下限为10, 所以+10,*10
c.要能够取到50,int强制转换是相当于向下取整,所以+51,*50
d.使用nextBoolean(),在加以三元运算符 ? : ,即可得到答案
以上均可再次使用Math.ceil()向上取整方法,具体不在列出
*/
}
}
}
示例学习·: 计算身体质量指数
- 你可以使用嵌套的if 语句来编写程序,计算身体质量指数
程序清单 3-4 ComputeAndInterpretBMI.java
import java.util.Scanner;
public class ComputeAndInterpretBMI {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
//Prompt the user to enter weight in pounds
System.out.print("Enter weight in pounds: ");
double weight = input.nextDouble();
//Prompt the user to enter height in inches
System.out.print("Enter height in inches: ");
double height = input.nextDouble();
final double KILOGRAMS_PER_POUNDS = 0.45359237;//Constant
final double METERS_PER_INCH = 0.0254;//Constant
//Compute BMI
double weightInKilograms = weight * KILOGRAMS_PER_POUNDS;
double heightInMeters = height * METERS_PER_INCH;
double bmi = weightInKilograms / (heightInMeters * heightInMeters);
//Display result
System.out.println("BMI is " + bmi);
if (bmi < 18.5)
System.out.println("Underweight");
else if (bmi < 25)
System.out.println("Normal");
else if (bmi < 30)
System.out.println("Overweight");
else
System.out.println("Obese");
}
}
示例学习: 计算税率
- 你可以使用嵌套的if 语句来计算税率
临界税率 | 单身纳税人 | 已婚共同纳税人或符合条件的鳏寡 | 已婚单独纳税人 | 家庭户主纳税人 |
---|---|---|---|---|
10% | $0 ~ $8350 | $0 ~ $16700 | $0 ~ $8350 | $0 ~ $11950 |
15% | $8351 ~ $33 950 | $16701 ~ $67900 | $8351~$33950 | $11951~$45500 |
25% | $33951 ~ $82 250 | $67901 ~ $137050 | $33951~$68525 | $45501~$117450 |
28% | $82251 ~ $171550 | $137051 ~ $208850 | $68526~$104425 | $117451~$190200 |
33% | $171551~$372950 | $208851 ~ $372950 | $104426~$186475 | $190201~$372950 |
35% | $372951+ | $372951+ | $186476+ | $372951+ |
程序清单 3-5 ComputeTax.java
import java.util.Scanner;
public class ComputeTax {
public static void main(String[] args) {
//Create a Scanner
Scanner input = new Scanner(System.in);
//Prompt the uesr to enter filing status
System.out.print("(0-single filer, 1- married jointly or " +
"qualifying widow(er),\n2-married separately, 3-head of " +
"household) Enter the filing status: ");
int status = input.nextInt();
//Prompt the user to enter taxable income
System.out.print("Enter the taxable income: ");
double income = input.nextDouble();
//Compute tax
double tax = 0;
if (status == 0) {//Compute tax for single filers
if (income <= 8350)
tax = income * 0.10;
else if (income <= 33950)
tax = 8350 * 0.10 + (income - 8350) * 0.15;
else if (income <= 82250)
tax = 8350 * 0.10 + (33950 - 8350) * 0.15 + (income - 33950) * 0.25;
else if (income <= 171550)
tax = 8350 * 0.10 + (33950 - 8350) * 0.15 +
(82250 - 33950) * 0.25 + (income - 82250) * 0.28;
else if (income <= 372950)
tax = 8350 * 0.10 + (33950 - 8350) * 0.15 +
(82250 - 33950) * 0.25 + (171550 - 82250) * 0.28 + (income - 171550) * 0.33;
else
tax = 8350 * 0.10 + (33950 - 8350) * 0.15 +
(82250 - 33950) * 0.25 + (171550 - 82250) * 0.28 +
(372950 - 171550) * 0.33 + (income - 372950) * 0.35;
} else if (status == 1) {//Left as an exercise
//Compute tax for married file jointly or qualifying widow(er)
} else if (status == 2) {//Compute tax for married separately
//Left as an exercise in Programming Exercise 3.13
} else if (status == 3) {//
//Left as an exercise in Programming Exercise 3.13
} else {
System.out.println("Error:invalid status");
System.exit(1);
}
//Display the result
System.out.println("Tax is " + (int) (tax * 100) / 100.0);
}
}
- 对所有的程序都应该先编写少量代码然后进行测试,之后在继续添加更多的代码。这个过程称为递进式开发和测试(incremental development and testing)。这种方法使得调试变得更加容易,因为错误很可能就在你刚刚添加进去的新代码中
逻辑运算符
- 逻辑操作符!、&&、||、^可以用于产生复合布尔表达式
操作符 | 名称 | 说明 |
---|---|---|
! | 非 | 逻辑非 |
&& | 与 | 逻辑与 |
|| | 或 | 逻辑或 |
^ | 异或 | 逻辑异或 |
p | !p | 举例(假设age = 24,weight = 140) |
---|---|---|
true | false | !(age>18) 为false,因为(age>18)为true |
false | true | !(weight==150)为true,因为(weight == 150)为false |
p1 | p2 | p1&&p2 | 举例(假设age = 24,weight = 140) |
---|---|---|---|
false | false | false | |
false | true | false | (age>28) && (weight<=140)为false,因为(age>28)为false |
true | false | false | |
true | true | true | (age>18) && (weight>=140)为true,因为(age>18)和(weight>=140)都为true |
p1 | p2 | p1&&p2 | 举例(假设age = 24,weight = 140) |
---|---|---|---|
false | false | false | (age>34) || (weight>150)为false,因为(age>34)和(weight>150)都为false |
false | true | true | |
true | false | true | (age>18) || (weight<140)为true,因为(age>18)为true |
true | true | true | 、 |
p1 | p2 | p1&&p2 | 举例(假设age = 24,weight = 140) |
---|---|---|---|
false | false | false | (age>34) ^(weight>140)为false,因为(age>34)和(weight>140)都为false |
false | true | true | |
true | false | true | (age>34) ^ (weight>=140)为true,因为(age>34)为false,但是(weight>=140)为true |
true | true | false |
程序清单 3-6 TestBooleanOperators.java
import java.util.Scanner;
public class TestBooleanOperators {
public static void main(String[] args) {
//Create a Scanner
Scanner input = new Scanner(System.in);
//Receive an input
System.out.print("Enter an integer: ");
int number = input.nextInt();
if (number % 2 == 0 && number % 3 == 0)//与 二者均为真
System.out.println(number + " is divisible by 2 and 3.");
if (number % 2 == 0 || number % 3 == 0)//或 二者有一个为真即可
System.out.println(number + " is divisible by 2 or 3");
if (number % 2 == 0 ^ number % 3 == 0)//异或 二者有且仅有一个为真
System.out.println(number + " is divisible by 2 or 3, but not both");
}
}
- 从数学的角度看,表达式1 <= numberOfDaysInAMonth <= 31是正确的。但是,在Java中它是错的,因为1<= numberOfDaysInAMonth得到的是一个布尔值的结果,它是不能和31进行比较的。这里的两个操作数(一个布尔值和一个数值)是不兼容的。正确的Java表达式是:
28 <= numberOfDaysInAMonth && numberOfDaysInAMonth
- 德摩根定律是以印度出生的英国数学家和逻辑学家奥古斯都·德·摩根(1806-1871)来命名的。这个定律可以用来简化表达式。定义表述如下:
!(condition1 && condition2) is the same as
!(condition1 || condition2)
!(condition1 || condition2) is the same as
!(condition1 && condition2)
示例学习:判定闰年
- 如果某年可以被4整除而不能被100整除,或者可以被400整除,那么这一年就是闰年
程序清单 3-7 LeapYear.java
import java.util.Scanner;
public class LeapYear {
public static void main(String[] args) {
//Create a Scanner
Scanner input = new Scanner(System.in);
System.out.print("Enter a year: ");
int year = input.nextInt();
//Check if the year is a leap year
boolean isLeepYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
//Display the rusult
System.out.println(year + " is a leap year? " + isLeepYear);
}
}
示例学习:彩票
- 彩票程序设计随机数、比较数字各位,以及运用布尔操作符
程序清单 3-8 Lottery.java
import java.util.Scanner;
public class Lottery {
public static void main(String[] args) {
//Generate a lottery number
int lottery = (int) (Math.random() * 100);
//Prompt the user to enter a guess
Scanner input = new Scanner(System.in);
System.out.print("Enter your lottery pick(two digits): ");
int guess = input.nextInt();
//Get digits from lottery
int lotteryDigit1 = lottery / 10;
int lotteryDigit2 = lottery % 10;
//Get digits from guess
int guessDigit1 = guess / 10;
int guessDigit2 = guess % 10;
System.out.println("The lottery number is " + lottery);
//Check the guess
if (guess == lottery)
System.out.println("Exact match: you win $10,000");
else if (guessDigit2 == lotteryDigit1 && guessDigit1 == lotteryDigit2)
System.out.println("Match all digits: you win $3,000");
else if (guessDigit1 == lotteryDigit1 || guessDigit1 == lotteryDigit2
|| guessDigit2 == lotteryDigit1 || guessDigit2 == lotteryDigit2)
System.out.println("Match one digit: you win $1,000");
else
System.out.println("Sorry, no match");
}
}
switch语句
- switch语句基于变量或者表达式的值来执行语句
- 不要忘记在需要的时候使用break语句。一旦匹配其中一个case,就从匹配的case处开始执行,直到遇到break语句或到达switch语句的结束。这种现象称为
落空行为(fall-through behavior)
(也称为switch穿透行为)。例如,下列代码为周一到周五显示Weekdays,为周日和周六显示Weekends。 - 为了避免程序设计错误,提高代码的可维护性,如果刻意省略break,在case子句后添加注释是一个好的做法
- year % 12 确定生肖。1900属鼠,因为1900 % 12 为4。程序清单 3-9 给出一个程序,提示用户输入一个年份,显示当年的生肖动物
- 不要忘记在需要的时候使用break语句。一旦匹配其中一个case,就从匹配的case处开始执行,直到遇到break语句或到达switch语句的结束。这种现象称为
程序清单 3.9 ChineseZodiac.java
import java.util.Scanner;
public class ChineseZodiac {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter a year:");
int year = input.nextInt();
switch (year % 12) {
case 0:
System.out.println("monkey");
break;
case 1:
System.out.println("rooster");
break;
case 2:
System.out.println("dog");
break;
case 3:
System.out.println("pig");
break;
case 4:
System.out.println("rat");
break;
case 5:
System.out.println("ox");
break;
case 6:
System.out.println("tiger");
break;
case 7:
System.out.println("rabbit");
break;
case 8:
System.out.println("dragon");
break;
case 9:
System.out.println("snake");
break;
case 10:
System.out.println("horse");
break;
case 11:
System.out.println("sheep");
break;
}
}
}
条件操作
- 条件操作基于一个条件计算表达式的值
操作符的优先级和结合规则
- 操作符的优先级和结合规则确定了操作符计算的顺序
优先级 | 操作符 |
---|---|
| | var++和var—(后置操作符) |
| | +、-(一元加号和一元减号)、++var、—var(前置操作符) |
| | (type)(类型转换) |
| | ! (非) |
| | *、/、% (乘法、除法和求余运算) |
| | +、-(二元加号和减号) |
| | <、<=、>、=>(比较操作符) |
| | ==、!=(相等操作符) |
| | ^(异或) |
| | &&(条件与) |
| | ||(条件或) |
V | =、+=、-=、*=、/=、%= (赋值操作符) |
调试
- 调试是在程序中找到和修改错误的过程
- 调试器都支持以下大部分的有用的特征
- 一次执行一条语句
- 调试器允许你一次执行一条语句,从而可以看到每条语句的效果
- 跟踪进入或者一步运行一个方法
- 如果一个方法正在被执行,可以让调试器跟踪进入方法内部,并且一次执行方法里面的一条语句,或者也可以让调试器一步运行整个方法。如果你知道方法是正确工作的,应该一次运行整个方法。比如,通常都会一步运行系统提供的方法,比如System.out.println
- 设置断点
- 你也可以在一条特定的语句上面设置断点。当遇到一个断点时,程序将暂停。可以设置任意多的断点。当你知道程序错误从什么地方可能开始的时候,断点特别有用。你可以将断点设置在那条语句上,让程序先执行到断点处
- 显示变量
- 调试器让你选择多个变量并且显示它们的值。当你跟踪一个程序的时候,变量的内容持续更新
- 显示调用堆栈
- 调试器让你跟踪所有的方法调用。当你需要看到程序执行流程的整体过程时,这个特征非常有用
- 修改变量
- 一些调试器允许你在调试的过程中修改变量的值。当你希望用不同的示例来测试程序,而又不希望离开调试器的时候,这是非常方便的。
- 一次执行一条语句