目录
控制流程
块作用域
块(block)(即复合语句)由若干条 Java 语句组成,并用一对大括号括起来。块确定了变量的作用域。一个块可以嵌套在另一个块中,但是不能在嵌套的两个块中声明同名变量。
public static void main(String[] args)
{
int n;
. . .
// 嵌套在 main 方法中的块:
{
int k;
int n; // 不可以定义与上级块中同名的变量
. . .
}
}
条件语句
形式一
if (condition) statement
这里的条件必须用小括号括起来
if (yourSales >= target)
{
performance = "Satisfactory";
bonus = 100;
}
if流程图:
形式二
if (condition) statement1 else statement2
if (yourSales >= target)
{
performance = "Satisfactory";
bonus = 100 + 0.01 * (yourSales - target);
}
else
{
performance = "Unsatisfactory";
bonus = 0;
}
// unsatisfactory adj.不令人满意的,不符合要求的
if...else... 流程图 :
形式三
反复使用 if...else if...
if (yourSales >= 2 * target)
{
performance = "Excellent";
bonus = 1000;
}
else if (yourSales >= 1.5 * target)
{
performance = "Fine";
bonus = 500;
}
else if (yourSales >= target)
{
performance = "Satisfactory";
bonus = 100;
}
else
{
System.out.println("You're fired");
}
/**
target n.目标
performance n.表现
bonus n.奖金
excellent adj.极好的,卓越的
fine adj.好的
satisfactory adj.令人满意的
fire v.解雇
*/
反复使用 if...else if... 流程图 :
循环
循环一
while 循环会在条件为 true 时执行一个语句(也可以是一个块语句)。
如果开始循环条件就为 false,那么 while 循环一次也不执行
// 计算需要多长时间才能够存下一定数量的退休金,假设每年存入相同金额,而且利率是固定的
while (balance < goal)
{
balance += payment;
double interest = balance * interestRate / 100;
balance += interest;
years++;
}
/**
payment n.付款
balance n.余额
interest n.利息
*/
while 语句的流程图 :
wile 计算退休金完整代码:
import java.util.*;
/**
* This program demonstrates a <code>while</code> loop.
*
* @author Cay Horstmann
* @version 1.20 2004-02-10
*/
public class Retirement {
public static void main(String[] args) {
// 读取输入
Scanner in = new Scanner(System.in);
System.out.print("How much money do you need to retire? ");
double goal = in.nextDouble();
System.out.print("How much money will you contribute every year? ");
double payment = in.nextDouble();
System.out.print("Interest rate in %: ");
double interestRate = in.nextDouble();
double balance = 0;
int years = 0;
// update account balance while goal isn't reached
while (balance < goal) {
// add this year's payment and interest
balance += payment;
double interest = balance * interestRate / 100;
balance += interest;
years++;
}
System.out.println("You can retire in " + years + " years.");
}
}
循环二
do statement while (condition)
这种循环先执行语句(通常是一个语句块),然后再检查循环条件。如果条件为 true,就重复执行语句,然后再此检测循环条件,以此类推。
do
{
balance += payment;
double interest = balance * interestRate / 100;
balance += interest;
years++;
// print current balance
. . .
// ask if ready to retire and get input
. . .
}
while (input.equals("N"));
do/while 语句的流程图:
do/while 计算退休金完整代码 :
import java.util.*;
/**
* This program demonstrates a <code>do/while</code> loop.
*
* @author Cay Horstmann
* @version 1.20 2004-02-10
*/
public class Retirement2 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("How much money will you contribute every year? ");
double payment = in.nextDouble();
System.out.print("Interest rate in %: ");
double interestRate = in.nextDouble();
double balance = 0;
int year = 0;
String input;
// update account balance while user isn't ready to retire
do {
// add this year's payment and interest
balance += payment;
double interest = balance * interestRate / 100;
balance += interest;
year++;
// print current balance
System.out.printf("After year %d, your balance is %,.2f%n", year,
balance);
// ask if ready to retire and get input
System.out.print("Ready to retire? (Y/N) ");
input = in.next();
}
while (input.equals("N"));
}
}
确定性循环
for (初始条件; 循环检测条件; 循环后更新计数器) {
// 执行语句
}
一些规则:
1.for 语句的 3 个部分应该对同一个计数器变量进行初始化、检测和更新。若不遵守,所写的循环可能晦涩难懂。
2.在 for 语句的第 1 部分中声明一个变量之后,这个变量的作用域会扩展到这个 for 循环体的末尾。
3.如果在 for 语句内部定义一个变量,这个变量就不能在循环体之外使用。因此,如果希望在 for 循环体之外使用循环计数器的最终值,就要确保在循环体之外声明这个变量。
4.可以在不同的 for 循环中定义同名的变量
5.for 循环语句只是 while 循环的一种简化形式。
警告:在循环中,检测连个浮点数是否相等需要格外小心。下面的 for 循环:
for (double x = 0; x != 10; x += 0.1) . . .
可能永远不会结束。由于存在舍入误差,可能永远达不到精确的最终值。在这个例子中,因为0.1无法精确地用二进制表示,所以,x 将从 9.99999999999998 跳到 10.09999999999998。
for 语句的流程图:
for 循环计算抽奖概率代码 :
一般情况下,如果从 n 个数字中抽取 k 个数字,就会有:
种可能。
import java.util.*;
/**
* This program demonstrates a <code>for</code> loop.
* @version 1.20 2004-02-10
* @author Cay Horstmann
*/
public class LotteryOdds
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
System.out.print("How many numbers do you need to draw? ");
int k = in.nextInt();
System.out.print("What is the highest number you can draw? ");
int n = in.nextInt();
/*
* compute binomial coefficient n*(n-1)*(n-2)*...*(n-k+1)/(1*2*3*...*k)
*/
int lotteryOdds = 1;
for (int i = 1; i <= k; i++)
lotteryOdds = lotteryOdds * (n - i + 1) / i;
System.out.println("Your odds are 1 in " + lotteryOdds + ". Good luck!");
}
}
多重选择:switch 语句
Scanner in = new Scanner(System.in);
System.out.print("Select an option (1, 2, 3, 4) ");
int choice = in.nextInt();
switch (choice)
{
case 1 ->
. . .
case 2 ->
. . .
case 3 ->
. . .
case 4 ->
. . .
default ->
System.out.println("Bad input");
}
以上代码是根据下面的流程图所创建出来的,其中
case 标签可以是:
1.类型为 char、byte、short 或 int 的常量表达式
2.枚举常量
3.字符串字面量
4.多个字符串,用逗号分隔
switch 语句的流程图:
switch 语句从与选项值相匹配的 case 标签开始执行,直到遇到下一个 break 语句,或者执行到 switch 语句结束。如果没有匹配的 case 标签,则执行 default 子句(如果有 default 子句)。
警告: 有可能触发多个分支。如果忘记在一个分支末尾增加 break 语句,就会接着执行下一个分支!这种情况相当危险,常常会引发错误。
为了检测这种问题,编译代码时可以加上 -Xlint:fallthrough 选项,如下所示:
javac -Xlint:fallthrough Test.java
这样一来,如果某个分支最后缺少一个 break 语句,编译器就会给出一个警告。
如果你确实想使用这种“直通式”(fallthrough)行为,可以为其外围方法加一个注解@SuppressWarnings("fallthrough")。这样就不会对这个方法生成警告了。(注解是为编译器或处理 Java 源文件或类文件的工具提供信息的一种机制。卷 Ⅱ 会深入介绍注解。)
4 种 switch 形式:
选择:switch 表达式优于语句,无直通行为由于有直通行为
注解:完全可以在 switch 表达式的一个分支中抛出异常。例如:
default -> throw new IllegalArgumentException("Not a valid season");
警告:switch 表达式的关键是生成一个值(或者产生一个异常而失败)。不允许“跳出”switch表达式:
default -> { return -1; } // ERROR
具体来讲,不能在 switch 表达式中使用 return、break 或 continue 语句。
中断控制流程的语句
break 和 带标签的 break
continue 和 带标签的 continue
大数
如果基本的整数和浮点数不足以满足需求,那么可以使用 java.math 包中两个很有用的类:BigInteger 和 BigDecimal。
BigInteger 类实现任意精度的整数运算,BigDecimal 类实现任意精度的浮点数运算
使用静态的 valueOf 方法可以将一个普通的数转换为大数:
BigInteger a = BigInteger.valueOf(100);
对于更长的数,可以使用一个带字符串参数的构造器:
BigInteger reallyBig = new BigInteger("22554462626622626266...")
另外还有一些常量:BigInteger.ZERO、BigInteger.ONE、BigInteger.TEN、以及 Java 9 之后还增加了 BigInteger.TWO.
警告:对于 BigDecimal 类,总是应当使用带一个字符串参数的构造器。还有一个 BigDecimal(double)构造器,不过这个构造器本质上很容易产生舍入误差,例如,new BigDecimal(0.1) 会得到以下数位: 0.1000000000000000055511151231257827021181583404541015625。
计算抽奖概率代码:(从n个数中抽取k个数中奖概率)
import java.math.*;
import java.util.*;
/**
* This program uses big numbers to compute the odds of winning the grand prize in a lottery.
* @version 1.20 2004-02-10
* @author Cay Horstmann
*/
public class BigIntegerTest {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("How many numbers do you need to draw? ");
int k = in.nextInt();
System.out.print("What is the highest number you can draw? ");
BigInteger n = in.nextBigInteger();
/*
* compute binomial coefficient n*(n-1)*(n-2)*...*(n-k+1)/(1*2*3*...*k)
*/
BigInteger lotteryOdds = BigInteger.ONE;
for (int i = 1; i <= k; i++)
lotteryOdds = lotteryOdds.
multiply(n.subtract(BigInteger.valueOf(i - 1))).
divide(BigInteger.valueOf(i));
System.out.printf("Your odds are 1 in %s. Good luck!%n", lotteryOdds);
}
}
大数常见API: