引言

    • 程序可以基于条件决定执行哪些语句

    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

    1. import java.util.Scanner;
    2. public class AdditionQuiz {
    3. public static void main(String[] args) {
    4. int number1 = (int) (System.currentTimeMillis() % 10);
    5. int number2 = (int) (System.currentTimeMillis() / 10 % 10);
    6. //Create a Scanner
    7. Scanner input = new Scanner(System.in);
    8. System.out.print(
    9. "What is " + number1 + " + " + number2 + " ? ");
    10. int answer = input.nextInt();
    11. System.out.println(number1 + " + " + number2 + " = " + answer + " is " +
    12. (number1 + number2 == answer));
    13. }
    14. }

    if语句

    • if语句是一个构造,允许程序确定执行的可选路径
    • 单分支if语句
      • 是指当且仅当条件为true时执行一个动作,其语法如下
        1. if(布尔表达式){
        2. 语句(组);
        3. }
    • 流程图是描述算法或者过程的图,以各种盒子显示步骤,并且通过箭头连接它们给出顺序。处理操作显示在这些盒子中,连接它们的箭头代表控制流程。棱形的盒子表示一个布尔类型的条件,矩形盒子代表语句。
    • 省略括号可以让代码更加简短,但是容易产生错误。当你返回去修改略去括号的代码的时候,容易忘记加上括号

    程序清单 3-2 SimpleIfDemo.java

    1. import java.util.Scanner;
    2. public class SimpleIfDemo {
    3. public static void main(String[] args) {
    4. Scanner input = new Scanner(System.in);
    5. System.out.print("Enter an integer: ");
    6. int number = input.nextInt();
    7. if (number % 5 == 0)
    8. System.out.println("HiFive");
    9. if (number % 2 == 0)
    10. System.out.println("HiEven");
    11. }
    12. }

    双分支if - else语句

    • if - else 语句根据条件是真或者是假,决定执行的路径
      1. if(布尔表达式){
      2. 布尔表达式为真时执行的语句(组);
      3. }
      4. else{
      5. 布尔表达式为假时执行的语句(组);
      6. }

    嵌套的if语句和多分支if - else 语句

    • if 语句可以在另外一个if语句中,形成嵌套的if语句

    常见错误和陷阱

    • 忘记必要的括号,在错误的地方结束if语句,将==错当作=来使用,悬空else分支,是选择语句中常见的错误。if - else语句中重复的语句,以及测试双精度值的相等是常见的陷阱。
    • 常见错误:
      • 忘记必要的括号
        1. //错误的
        2. if(radius >= 0)
        3. area = radius * radius * PI;
        4. System.out.println("The area " + " is " + area);
        5. //正确的
        6. if(radius >= 0){
        7. area = radius * radius * PI;
        8. System.out.println("The area " + " is " + area);
        9. }
        10. //错误的等价于
        11. if(radius >= 0)
        12. area = radius * radius * PI;
        13. System.out.println("The area " + " is " + area);
    • 错误地在if行出现分号
      1. //逻辑错误
      2. if(radius >= 0);//error
      3. {
      4. area = radius * radius * PI;
      5. System.out.println("The area " + " is " + area);
      6. }
      7. //等价于
      8. if(radius >= 0){ };//error 空的块
      9. {
      10. area = radius * radius * PI;
      11. System.out.println("The area " + " is " + area);
      12. }
    • 对布尔值的冗余测试
      1. if (even == true)
      2. System.out.println("It is even");
      3. //等价于 这种更好
      4. if(even)
      5. 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”);

    1. - 两个浮点数值的相等测试
    2. - 浮点数具有有限的计算精度;涉及浮点数的计算可能引入舍入错误。因此,两个浮点数值的相等测试并不可靠
    3. ```java
    4. final double EPSILON = 1E-14;//注意,这里不要空格
    5. double x = 1.0 -0.1-0.1-0.1-0.1-0.1;
    6. if (Math.abs(x - 0.5) < EPSILON)
    7. System.out.println(x + " is approximately 0.5);
    • 常见陷阱:
      • 简化布尔变量赋值
        1. if(number % 2 == 0)
        2. even = true;
        3. else
        4. even = false;
        5. //等价于
        6. boolean even
        7. = number % 2 == 0;
    • 避免不同情形中的重复代码
      1. //代码冗余
      2. if(inState){
      3. tuition = 5000;
      4. System.out.println("The tuition is " + tuition);
      5. }
      6. else{
      7. tuition = 15000;
      8. System.out.println("The tuition is " + tuition);
      9. }
      10. //等价于
      11. if(inState){
      12. tuition = 5000;
      13. }
      14. else{
      15. tuition = 15000;
      16. }
      17. System.out.println("The tuition is " + tuition);

    产生随机数

    • 你可以使用Math.random()来获得一个0.0到1.0之间的随机double值,不包括1.0

    程序清单 3-3 SubtractionQuiz.java

    1. import java.util.Scanner;
    2. public class SubtractionQuiz {
    3. public static void main(String[] args) {
    4. // 1.Generate two random single-digit integers
    5. int number1 = (int) (Math.random() * 10);
    6. int number2 = (int) (Math.random() * 10);
    7. //2. If number1 <number2,swap number1 with number2
    8. if (number1 < number2) {
    9. int temp = number1;
    10. number1 = number2;
    11. number2 = temp;
    12. }
    13. //3. Prompt the student to answer "What is number1 - number2?"
    14. System.out.print("What is " + number1 + " - " + number2 + " ? ");
    15. Scanner input = new Scanner(System.in);
    16. int answer = input.nextInt();
    17. //4.Grade the answer and display the result
    18. if (number1 - number1 == answer)
    19. System.out.println("You are correct!");
    20. else {
    21. System.out.println("Your answer is wrong.");
    22. System.out.println(number1 + " - " + number2 +
    23. " should be " + (number1 - number2));
    24. }
    25. }
    26. }
    1. a.产生一个随机整数i,使得0<= i < 20?
    2. b.产生一个随机整数i,使得10<= i < 20?
    3. c.产生一个随机整数i,使得0<= i <= 50?
    4. d.编写一个表达式,随机返回0或者1
    5. import java.util.Random;
    6. public class sa {
    7. public static void main(String[] args) {
    8. Random random = new Random();
    9. for (int i = 0; i < 100; i++) {
    10. System.out.println((int)(random.nextDouble()*20));//a
    11. System.out.println((int)(random.nextDouble()*10 + 10));//b
    12. System.out.println((int)(random.nextDouble()*+ 51));//c
    13. System.out.println(random.nextBoolean()?1:0);//d
    14. /*分析
    15. a.因为取不到1.0的值,要求0<= i < 20,只需 * 20即可
    16. b.下限为10, 所以+10,*10
    17. c.要能够取到50,int强制转换是相当于向下取整,所以+51,*50
    18. d.使用nextBoolean(),在加以三元运算符 ? : ,即可得到答案
    19. 以上均可再次使用Math.ceil()向上取整方法,具体不在列出
    20. */
    21. }
    22. }
    23. }

    示例学习·: 计算身体质量指数

    • 你可以使用嵌套的if 语句来编写程序,计算身体质量指数

    程序清单 3-4 ComputeAndInterpretBMI.java

    1. import java.util.Scanner;
    2. public class ComputeAndInterpretBMI {
    3. public static void main(String[] args) {
    4. Scanner input = new Scanner(System.in);
    5. //Prompt the user to enter weight in pounds
    6. System.out.print("Enter weight in pounds: ");
    7. double weight = input.nextDouble();
    8. //Prompt the user to enter height in inches
    9. System.out.print("Enter height in inches: ");
    10. double height = input.nextDouble();
    11. final double KILOGRAMS_PER_POUNDS = 0.45359237;//Constant
    12. final double METERS_PER_INCH = 0.0254;//Constant
    13. //Compute BMI
    14. double weightInKilograms = weight * KILOGRAMS_PER_POUNDS;
    15. double heightInMeters = height * METERS_PER_INCH;
    16. double bmi = weightInKilograms / (heightInMeters * heightInMeters);
    17. //Display result
    18. System.out.println("BMI is " + bmi);
    19. if (bmi < 18.5)
    20. System.out.println("Underweight");
    21. else if (bmi < 25)
    22. System.out.println("Normal");
    23. else if (bmi < 30)
    24. System.out.println("Overweight");
    25. else
    26. System.out.println("Obese");
    27. }
    28. }

    示例学习: 计算税率

    • 你可以使用嵌套的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

    1. import java.util.Scanner;
    2. public class ComputeTax {
    3. public static void main(String[] args) {
    4. //Create a Scanner
    5. Scanner input = new Scanner(System.in);
    6. //Prompt the uesr to enter filing status
    7. System.out.print("(0-single filer, 1- married jointly or " +
    8. "qualifying widow(er),\n2-married separately, 3-head of " +
    9. "household) Enter the filing status: ");
    10. int status = input.nextInt();
    11. //Prompt the user to enter taxable income
    12. System.out.print("Enter the taxable income: ");
    13. double income = input.nextDouble();
    14. //Compute tax
    15. double tax = 0;
    16. if (status == 0) {//Compute tax for single filers
    17. if (income <= 8350)
    18. tax = income * 0.10;
    19. else if (income <= 33950)
    20. tax = 8350 * 0.10 + (income - 8350) * 0.15;
    21. else if (income <= 82250)
    22. tax = 8350 * 0.10 + (33950 - 8350) * 0.15 + (income - 33950) * 0.25;
    23. else if (income <= 171550)
    24. tax = 8350 * 0.10 + (33950 - 8350) * 0.15 +
    25. (82250 - 33950) * 0.25 + (income - 82250) * 0.28;
    26. else if (income <= 372950)
    27. tax = 8350 * 0.10 + (33950 - 8350) * 0.15 +
    28. (82250 - 33950) * 0.25 + (171550 - 82250) * 0.28 + (income - 171550) * 0.33;
    29. else
    30. tax = 8350 * 0.10 + (33950 - 8350) * 0.15 +
    31. (82250 - 33950) * 0.25 + (171550 - 82250) * 0.28 +
    32. (372950 - 171550) * 0.33 + (income - 372950) * 0.35;
    33. } else if (status == 1) {//Left as an exercise
    34. //Compute tax for married file jointly or qualifying widow(er)
    35. } else if (status == 2) {//Compute tax for married separately
    36. //Left as an exercise in Programming Exercise 3.13
    37. } else if (status == 3) {//
    38. //Left as an exercise in Programming Exercise 3.13
    39. } else {
    40. System.out.println("Error:invalid status");
    41. System.exit(1);
    42. }
    43. //Display the result
    44. System.out.println("Tax is " + (int) (tax * 100) / 100.0);
    45. }
    46. }
    • 对所有的程序都应该先编写少量代码然后进行测试,之后在继续添加更多的代码。这个过程称为递进式开发和测试(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

    1. import java.util.Scanner;
    2. public class TestBooleanOperators {
    3. public static void main(String[] args) {
    4. //Create a Scanner
    5. Scanner input = new Scanner(System.in);
    6. //Receive an input
    7. System.out.print("Enter an integer: ");
    8. int number = input.nextInt();
    9. if (number % 2 == 0 && number % 3 == 0)//与 二者均为真
    10. System.out.println(number + " is divisible by 2 and 3.");
    11. if (number % 2 == 0 || number % 3 == 0)//或 二者有一个为真即可
    12. System.out.println(number + " is divisible by 2 or 3");
    13. if (number % 2 == 0 ^ number % 3 == 0)//异或 二者有且仅有一个为真
    14. System.out.println(number + " is divisible by 2 or 3, but not both");
    15. }
    16. }
    • 从数学的角度看,表达式1 <= numberOfDaysInAMonth <= 31是正确的。但是,在Java中它是错的,因为1<= numberOfDaysInAMonth得到的是一个布尔值的结果,它是不能和31进行比较的。这里的两个操作数(一个布尔值和一个数值)是不兼容的。正确的Java表达式是:
      1. 28 <= numberOfDaysInAMonth && numberOfDaysInAMonth
    • 德摩根定律是以印度出生的英国数学家和逻辑学家奥古斯都·德·摩根(1806-1871)来命名的。这个定律可以用来简化表达式。定义表述如下:
      1. !(condition1 && condition2) is the same as
      2. !(condition1 || condition2)
      3. !(condition1 || condition2) is the same as
      4. !(condition1 && condition2)

    示例学习:判定闰年

    • 如果某年可以被4整除而不能被100整除,或者可以被400整除,那么这一年就是闰年

    程序清单 3-7 LeapYear.java

    1. import java.util.Scanner;
    2. public class LeapYear {
    3. public static void main(String[] args) {
    4. //Create a Scanner
    5. Scanner input = new Scanner(System.in);
    6. System.out.print("Enter a year: ");
    7. int year = input.nextInt();
    8. //Check if the year is a leap year
    9. boolean isLeepYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
    10. //Display the rusult
    11. System.out.println(year + " is a leap year? " + isLeepYear);
    12. }
    13. }

    示例学习:彩票

    • 彩票程序设计随机数、比较数字各位,以及运用布尔操作符

    程序清单 3-8 Lottery.java

    1. import java.util.Scanner;
    2. public class Lottery {
    3. public static void main(String[] args) {
    4. //Generate a lottery number
    5. int lottery = (int) (Math.random() * 100);
    6. //Prompt the user to enter a guess
    7. Scanner input = new Scanner(System.in);
    8. System.out.print("Enter your lottery pick(two digits): ");
    9. int guess = input.nextInt();
    10. //Get digits from lottery
    11. int lotteryDigit1 = lottery / 10;
    12. int lotteryDigit2 = lottery % 10;
    13. //Get digits from guess
    14. int guessDigit1 = guess / 10;
    15. int guessDigit2 = guess % 10;
    16. System.out.println("The lottery number is " + lottery);
    17. //Check the guess
    18. if (guess == lottery)
    19. System.out.println("Exact match: you win $10,000");
    20. else if (guessDigit2 == lotteryDigit1 && guessDigit1 == lotteryDigit2)
    21. System.out.println("Match all digits: you win $3,000");
    22. else if (guessDigit1 == lotteryDigit1 || guessDigit1 == lotteryDigit2
    23. || guessDigit2 == lotteryDigit1 || guessDigit2 == lotteryDigit2)
    24. System.out.println("Match one digit: you win $1,000");
    25. else
    26. System.out.println("Sorry, no match");
    27. }
    28. }

    switch语句

    • switch语句基于变量或者表达式的值来执行语句
      • 不要忘记在需要的时候使用break语句。一旦匹配其中一个case,就从匹配的case处开始执行,直到遇到break语句或到达switch语句的结束。这种现象称为落空行为(fall-through behavior)(也称为switch穿透行为)。例如,下列代码为周一到周五显示Weekdays,为周日和周六显示Weekends。
      • 为了避免程序设计错误,提高代码的可维护性,如果刻意省略break,在case子句后添加注释是一个好的做法
      • year % 12 确定生肖。1900属鼠,因为1900 % 12 为4。程序清单 3-9 给出一个程序,提示用户输入一个年份,显示当年的生肖动物

    程序清单 3.9 ChineseZodiac.java

    1. import java.util.Scanner;
    2. public class ChineseZodiac {
    3. public static void main(String[] args) {
    4. Scanner input = new Scanner(System.in);
    5. System.out.print("Enter a year:");
    6. int year = input.nextInt();
    7. switch (year % 12) {
    8. case 0:
    9. System.out.println("monkey");
    10. break;
    11. case 1:
    12. System.out.println("rooster");
    13. break;
    14. case 2:
    15. System.out.println("dog");
    16. break;
    17. case 3:
    18. System.out.println("pig");
    19. break;
    20. case 4:
    21. System.out.println("rat");
    22. break;
    23. case 5:
    24. System.out.println("ox");
    25. break;
    26. case 6:
    27. System.out.println("tiger");
    28. break;
    29. case 7:
    30. System.out.println("rabbit");
    31. break;
    32. case 8:
    33. System.out.println("dragon");
    34. break;
    35. case 9:
    36. System.out.println("snake");
    37. break;
    38. case 10:
    39. System.out.println("horse");
    40. break;
    41. case 11:
    42. System.out.println("sheep");
    43. break;
    44. }
    45. }
    46. }

    条件操作

    • 条件操作基于一个条件计算表达式的值

    操作符的优先级和结合规则

    • 操作符的优先级和结合规则确定了操作符计算的顺序
    优先级 操作符
    | var++和var—(后置操作符)
    | +、-(一元加号和一元减号)、++var、—var(前置操作符)
    | (type)(类型转换)
    | ! (非)
    | *、/、% (乘法、除法和求余运算)
    | +、-(二元加号和减号)
    | <、<=、>、=>(比较操作符)
    | ==、!=(相等操作符)
    | ^(异或)
    | &&(条件与)
    | ||(条件或)
    V =、+=、-=、*=、/=、%= (赋值操作符)

    调试

    • 调试是在程序中找到和修改错误的过程
    • 调试器都支持以下大部分的有用的特征
      • 一次执行一条语句
        • 调试器允许你一次执行一条语句,从而可以看到每条语句的效果
      • 跟踪进入或者一步运行一个方法
        • 如果一个方法正在被执行,可以让调试器跟踪进入方法内部,并且一次执行方法里面的一条语句,或者也可以让调试器一步运行整个方法。如果你知道方法是正确工作的,应该一次运行整个方法。比如,通常都会一步运行系统提供的方法,比如System.out.println
      • 设置断点
        • 你也可以在一条特定的语句上面设置断点。当遇到一个断点时,程序将暂停。可以设置任意多的断点。当你知道程序错误从什么地方可能开始的时候,断点特别有用。你可以将断点设置在那条语句上,让程序先执行到断点处
      • 显示变量
        • 调试器让你选择多个变量并且显示它们的值。当你跟踪一个程序的时候,变量的内容持续更新
      • 显示调用堆栈
        • 调试器让你跟踪所有的方法调用。当你需要看到程序执行流程的整体过程时,这个特征非常有用
      • 修改变量
        • 一些调试器允许你在调试的过程中修改变量的值。当你希望用不同的示例来测试程序,而又不希望离开调试器的时候,这是非常方便的。