计算机最为强大的是可以快速进行重复运算,这就牵涉到循环
Java中提供循环可以控制对一个语句或一系列语句重复执行数次
int count = 0;
while(count<100){
System.out.println(“Welcome to Java”);
count++;
}
变量count的值为0,循环检查count<100是否为true,如果是true则会控制循环体输出Welcome to Java,然后把count加1,直到count<100为false时才不会执行循环体中语句
循环是程序设计的基础,Java提供了三种类型的循环:while循环、do-while循环、for循环
while循环:
while(循环判断条件){
循环体;
}
循环体的每一次执行都被看作是一次循环的迭代,循环判断条件是一个布尔表达式用来控制循环体的执行,每次在去执行循环体之前都会先判断循环条件是否为true为true时才会执行循环体中的语句
如果在一个循环结构中没有使用判断条件变为false的情况则这个循环会是一个死循环永远不会结束这个循环
在循环结构中最容易产生的错误就是使用循环体多执行一次或少执行一次的情况
下面的程序是随机产生一个0~100整数并且包括100,这个时候提示用户去猜这个数字,这个时候给出所猜数字与随机产生的数字之间的比较关系直到最后猜到数字为止
这个循环的去猜数字并不知道要猜多少次因而我们不能以次数来决定循环的次数而以输入的数字与随机产生的数字相等为结束的标识
import java.util.Random;
import java.util.Scanner;
publicclass GuessNumber {
publicstaticvoid main(String[] args) {
//获得一个[0,100]的随机数
Random random = new Random();
int number = random.nextInt(101);
//定义一个变量用来记录所猜的次数
int count = 1;
//提示用户输入一个所猜的数字
Scanner input = new Scanner(System.in);
System.out.print("请输入你所猜的数字[0,100]之间:");
int guess = input.nextInt();
while(guess != number){
if(number-guess<0){
System.out.println("你猜的数字过大!");
System.out.print("请重新输入你所猜的数字[0,100]之间:");
guess = input.nextInt();
count++;
} elseif(number-guess>0){
System.out.println("你猜的数字过小!");
System.out.print("请重新输入你所猜的数字[0,100]之间:");
guess = input.nextInt();
count++;
}
}
System.out.println("恭喜你猜对了!你总共猜了"+count+" 次");
}
}
关于循环的设计策略:
写一个循环要考虑到三个步骤:
1, 确定要重复的语句
2, 把这些重复的语句放到循环当中
while(true){
语句组;
}
3, 为循环要继续写上相应的条件把上面的true替换掉
while(循环条件){
语句组;
用于控制循环的附件语句;
}
如下程序可以做加上循环策略的一个小学一年级十位数以内的加减法的测试程序
import java.util.Random;
import java.util.Scanner;
import javax.swing.JOptionPane;
publicclass FirstGradeTest {
publicstaticvoid main(String[] args) {
//定义一个变量为要考试题数(常量)
finalint NUMBER_OF_QUESTIONS = 10;
//定义一个回答正确的题数
int correctCount = 0;
//定义一个当前的题数
int count = 0;
//定义一个变量用于存放用户的输入答案
int answer = 0;
//定义一个StringBuilder用来存放最后要输出的结果
StringBuilder sbMessage = new StringBuilder();
//定义一个获取随机数的的对象
Random random = new Random();
//定义一个Scanner扫描器类
Scanner input = new Scanner(System.in);
long startTime = System.currentTimeMillis();//计算开始考试的时间点
//
while(count<NUMBER_OF_QUESTIONS){
//得到两个用于计算的随机数
int number1 = random.nextInt(10);
int number2 = random.nextInt(10);
//如果得到的随机数1比随机数2小则两个随机数进行一下交换
if(number1<number2){
int temp = number1;
number1 = number2;
number2 = temp;
}
//判断是进行加法还是减法随机生成
if(random.nextInt(2)==1){
//进行加法,提示用户输入结果
System.out.print(number1+" + "+number2+" = "+" ? ");
//获得用户的输入
answer = input.nextInt();
if(answer == number1+number2){
sbMessage.append(number1+" + "+number2+" = "+answer+" 回答正确!\n");
correctCount++;
}else
sbMessage.append(number1+" + "+number2+" = "+answer+" 回答错误,正确答案应是: "+(number1+number2)+"\n");
count++;
}else{
//进行减法,提示用户输入结果
System.out.print(number1+" - "+number2+" = "+" ? ");
//获得用户的输入
answer = input.nextInt();
if(answer == number1-number2){
sbMessage.append(number1+" - "+number2+" = "+answer+" 回答正确!\n");
correctCount++;
}else
sbMessage.append(number1+" - "+number2+" = "+answer+" 回答错误,正确答案应是: "+(number1-number2)+"\n");
count++;
}
}
long endTime = System.currentTimeMillis();
JOptionPane.showMessageDialog(null, "这次测试总共用时:"+(endTime-startTime)/1000+"秒\n"+"测试得分为:"+correctCount*10+"\n"+"测试结果如下:\n"+sbMessage.toString(),"测试结果",JOptionPane.INFORMATION_MESSAGE);
}
}
这个程序使用一个count变量来控制循环的进行count被初始化为0每次执行一次循环体则会把它的值加1,程序中用了两个时间点来判断所有循环执行完成的用时情况在开始循环前取得一个当前的时间毫秒数,所有循环执行完后再取得一下毫秒数这两个数的差值则是运行这个循环的用时
使用标志值来控制循环:
这是一种常用来控制循环的方式,使用一个特殊的值来控制循环的执行与否,这种循环也称为标志位控制循环
import java.util.Scanner;
publicclass SentineValue {
publicstaticvoid main(String[] args) {
//获得一个Scanner扫描器对象
Scanner input = new Scanner(System.in);
//获得用户输入的值
System.out.print("请输入一个整数(0表示结束):");
int data = input.nextInt();
int sum = 0;
while(data != 0){
//循环体
sum += data;
System.out.print("请再次输入一个整数(0表示结束):");
data = input.nextInt();
}
//显示示执行完循环体后的结果
System.out.println("sum的最终值是: "+sum);
}
}
这个程序当用户输入的data不是0的时候会执行循环体把输入的结果加到sum中去并且提示次再次输入一个新的data值直到用户输入0的时候判断循环条件是false则会跳出循环
注意:在按制循环的时候不要使用浮点值来进行比较结果因为浮点值都是某些值的近似值这样得到的循环的次数可能不精确。
输入与输出的重定向:
在Java中如果要输入大量的值的时候如果从控制台使用键盘输入比较麻烦,这个时候可以把这些值用空格分开事先放到一个文本文档当中比如input.txt然后使用
java SentineValue < input.txt
这个命令就是输入重定向,这个时候程序从这个文件中去读数据而不是从控制台以键盘的方式输入
与之相对应的还有输出重定向使用的命令是:
java ClassName > output.txt
并且在Java中可以在同一命令当中同时使用输入和输出重定向命令
java SentineValue < input.txt > output.txt
do-while循环:
它是while循环的变体:
do{
循环体;
}while(循环继续条件);
它的执行过程是先执行循环体,然后计算循环继续的条件,如果计算的结果是true则去重复执行循环体,如果是false则终止do-while循环,这个过程与while循环的差别就在于计算循环继续的条件的顺序是不一样的一个在执行完循环体后计算一个在执行之前先去判断
对于那种不管条件怎么样都一定要执行至少一次的循环任务使用do-while是最为方便而且结构最为清晰的
import java.util.Scanner;
publicclass TestDoWhile {
publicstaticvoid main(String[] args) {
//创建一个扫描器对象
Scanner input = new Scanner(System.in);
int data = 0;
int sum = 0;
do{
//提示用户输入相应的值
System.out.print("请输入一个整数值(输入0结束):");
data = input.nextInt();
sum += data;
}while(data !=0);
System.out.println("sum的最终结果是:"+sum);
}
}
for循环:
经常在编程序的时候会用来下面的这种结构来写一个循环
i = initialValue;先对一下变量给定一个初始的变量
while(i < endValue){
循环体;
i++;
}
上面的循环结构可以使用下面的for循环简化
for(i = initialValue;i<endValue;i++){
循环体;
}
for循环的语法结构如下
for(初始操作;循环继续条件;每次迭代后的操作){
循环体;
}
for循环语句只执行一次初始化动作,当循环条件为真的时候会执行循环体然后完成每次迭代后的操作再进行循环继续条件
一般来说,for使用一个变量来控制循环体的执行次数,以及什么时候中止,这里的这个变量就是一个控制变量,初始化动作就是用来初始化这个控制变量,每次的迭代通常会对控制变量进行自增或自减
例如,还常常有如下的写法
for(int i=0;i<100;i++){
循环体;
}
这个时候如果循环控制变量只是在循环体中使用则在for循环头上声明并初始化这个循环变量是最为好的,这样的话在退出循环后就不可以对这个变量进行引用了防止了在循环体外再次对它引用而引起的错误
for循环可以写成for(;;){}这种写法不常用因为这种写法现while(true){}是等价的而后者更加清晰
对于while,for,do…while循环使用的选择:
for一般是针对明确的知道循环次数的循环
while一般是针对以相应的条件作为结束的循环不能明确确定循环要执行的次数
do…while与while循环类似不同之处在于它不管循环条件是否成立一定会执行一次循环体
嵌套循环:
由一个外层循环与一个或多个内层循环组成的,每当重复执行一次外层循环时就会进入内层的循环然后重新开始
import javax.swing.JOptionPane;
publicclass MultiplicationTable {
publicstaticvoid main(String[] args) {
//打印这个乘法表的表头
StringBuilder sb = new StringBuilder();
sb.append("────────九九乘法表────────\n");
//使用循环加上表标题行
for(int i = 1;i<=9;i++){
if(i==1)
sb.append(" "+i);
else
sb.append(" "+i);
}
sb.append("\n─────────────────────\n");
//使用嵌套循环生成乘法表中的内容
for(int i=1;i<=9;i++){
sb.append(i+" │ ");
for(int j=1;j<=i;j++){
if(i*j<10 && j>1)
sb.append(" "+i*j);
else
sb.append(" "+i*j);
}
sb.append("\n");
}
JOptionPane.showMessageDialog(null, sb.toString(),"九九乘法表",JOptionPane.INFORMATION_MESSAGE);
}
}
程序在循环中加上了if、else是为了控制打印的格式
在画出一个九九表的时候使用了一个嵌套循环去得到相乘的结果
最小化数值误差:
对于浮点数来说有计算过程中有误差是不可避免的,如下程序将说明如何最小化这种计算的误差:
publicclass TestSum {
publicstaticvoid main(String[] args) {
//声明一下浮点型变量
float sum = 0;
//做一个浮点数的累加循环
for(float i = 0.01f;i<=1.0f;i = i+0.01f)
sum += i;
//输出循环后的结果
System.out.println("最后sum的结果是:"+sum);
}
}
取后的结果是:
for循环的初始动作可以是任何语句,但它经常用来初始化控制变量,这里控制变量可以是float类型的,并且注意这里可以是任意类型的
对于sum如果是精确的计算的话应该是50.50,但运行后的结果明显不是精确的结果,这是因为在计算机中使用固定的位数来表示浮点数这样就使得对于每一个浮点数来说它是不能精确的表示的,如果把上面的程序中float类型改为double类型得到的结果精确度应该会大一些
在Java中如果要得到精确的结果可以如如下的程序:
import java.math.BigDecimal;
publicclass TestSum {
publicstaticvoid main(String[] args) {
// 声明一下浮点型变量
BigDecimal sum = new BigDecimal("0");
// 做一个浮点数的累加循环
for (BigDecimal i = new BigDecimal("0.01"); i.compareTo(new BigDecimal(
"1.0")) == -1 || i.compareTo(new BigDecimal("1.0")) == 0; i = i
.add(new BigDecimal("0.01"))) {
sum = sum.add(i);
}
// 输出循环后的结果
System.out.println("最后sum的结果是:" + sum);
}
}
注意BigDecimal类是在Java.math包中的要使用时要导入这个包,而且在创建这个类的时候调用构造函数传一个String类型过去才能得到精确的值,如果是传一个double类型过去一样得不到精确的结果,还是做相应的运算的时候不能用+这样的运算符而是要调用它的方法add,进行比较时调用它的方法compareTO(BigDecimal other);这个方法会返回1(大于),0(等于),-1(小于)
循环对于编写程序来说是非常重要的,如果能很好的利用循环的特性来编写程序则可以说就是懂得了编程
最大公约数:
两个整数取最大的公约数:
1,1是两整数的公约数所以假设默认最大的公约数是1
2,公约数一定会小于或等于两个数中最小的那个,所以先找到最小的那个数
4, 如果大数能整除小数则最大公约数就是两者中的小数
5, 如果不能整除则从2开始取到小于等于小数的那个数找到公约数就更新设了默认公约数的那个变量,循环完成后这个数就一定是最大公约数了
import java.util.Scanner;
publicclass GreatestCommonDivisor {
publicstaticvoid main(String[] args) {
// 声明一个变量保存最大公约数(默认为1)
int gys = 1;
// 创建一个Scanner类对象
Scanner input = new Scanner(System.in);
//提示用户输入两个正整数
System.out.print("请输入第一个正整数:");
int n1 = input.nextInt();
System.out.print("请输入第二个正整数:");
int n2 = input.nextInt();
//声明一变量来保存这两个数中的小者
int min = (n1<=n2)?n1:n2;
//找最大公约数
if(n1%min==0 && n2%min==0){
System.out.println(n1 + "与" + n2 + "的最大公约数是: " + min);
return;
}
else{
int k = 2;
while(k<min){
if(n1%k==0 && n2%k==0)
gys = k;
k++;
}
}
System.out.println(n1 + "与" + n2 + "的最大公约数是: " + gys);
}
}
编写程序之前要先思考的是逻辑方案,有了清晰的逻辑方案然后再把这个方案转为Java代码,在逻辑方案中一定要考虑到相应的特殊的值一般来说对于特殊的值会有直接的处理结果,并且不是按逻辑计算能得到的所以在进行逻辑之前把这些特殊的情况想清楚是很重要的
预测未来的房价:
假定某地的房价是10000,而且以每年7%的速度来增长,多少年后房价会翻倍
publicclass FuturePrice {
publicstaticvoid main(String[] args) {
//定义一个变量保存当前的房价
double price = 10000;
//定义一个变量保存计算的年数默认是1年
int year = 1;
//每年的房价以15%的速度来增长则每年计算后的房价与要判断的值做一个比较最后得到计算了多少年
while(price<20000){
price = price*1.15;
year++;
}
System.out.println(year+"年后房价会翻倍!");
}
}
关于蒙特卡罗模拟:
蒙特卡罗模似是使用随机数和概率来解决问题,使用它来估算∏的值
假设圆的半径是1则圆的面积就是∏而外接正方式的面积是4那么在这个正方形中随机产生一个点的话这个点落在圆中的概率是∏/4
现在在正方形内随机产生1000000个点,numberOfHits表示落在圆内的点,这时这个值大约是1000000*(∏/4),那么经转换的话则∏ = 4*numberOfHits/1000000;
publicclass PiValue {
publicstaticvoid main(String[] args) {
//这里指定要测试的点的个数
finalint NUMBER_OF_TEST = 10000000;
//声明一个变量存储点落在圆内的数量
int numberOfHits = 0;
//使用循环来得到这个测试的点数中有多少是会落在圆内的
for(int i = 0;i<NUMBER_OF_TEST;i++){
double x = Math.random()*2-1;
double y = Math.random()*2-1;
//判断随机产生的点是否在圆内如果在的话则把numberOfHits加1
if(x*x+y*y<=1)
numberOfHits++;
}
//计算∏的值
double pi = 4.0*numberOfHits/NUMBER_OF_TEST;
//除出结果
System.out.println("PI的值大约是:"+pi);
}
}
循环中常用关键字break,continue
在switch语句中已使用过break,也可以在一个循环当中使用break
publicclass TestBreak {
publicstaticvoid main(String[] args) {
int sum = 0;
int number = 0;
while (number < 20) {
number++;
sum += number;
if (sum > 100)
break;
}
//显示经过上面的循环后两个变量的结果
System.out.println("number的值为:"+number);
System.out.println("sum的值为:"+sum);
}
}
在上面的程序中如果没有if语句的话则程序会计算1到20时间的整数和,但有了if语句只要是sum的值大于100的时候就会退出循环
也可以在循环当中使用continue语句,当程序遇到了continue的时候,它会结速本次的循环,注意continue只是结束本一次循环而break是结束整个循环
publicclass TestContinue {
publicstaticvoid main(String[] args) {
int sum = 0;
int number = 0;
while (number < 20) {
number++;
if (number == 10 || number == 11)
continue;
sum += number;
}
// 输出最后的结果
System.out.println("sum的值为:" + sum);
}
}
从上面的结果输出为189可以看出当number为10或是11的时候没有把它的值累加进来
continue语句总是在一个循环内,在while和do-while循环中,continue语句后会计算循环控制条件而在for循环当中continue后会马上执行迭代后的动作然后再计算循环继续条件
对于循环来说总是可以不使用break,continue而使用它们是为了程序更加的简便,但是要注意使用得当要不然程序会变得难以阅读
import java.util.Random;
import java.util.Scanner;
publicclass GuessNumberUsingBreak {
publicstaticvoid main(String[] args) {
// 创建一个随机数生成器对象
Random random = new Random();
// 生成一个随机数
int number = random.nextInt(101);
// 创建一个控制输和对象
Scanner input = new Scanner(System.in);
// 提示用户进行输入
System.out.println("猜的数字(0~100)");
// 写一个无限循环当猜对的时候就break跳出循环,并定义一个变量进行记录猜的次数
int count = 0;
while (true) {
count++;
System.out.print("输入你猜的数字: ");
int guess = input.nextInt();
if (guess == number) {
System.out.println("正确,你猜对了!");
System.out.println("你一共猜了" + count + "次!");
break;
} elseif (guess > number)
System.out.println("你猜的数太大!");
else
System.out.println("你猜的数太小!");
}
}
}
关于素数问题:
大于1的整数,如果它的正因子只有1和它自身,那么这个整数就是素数
现要求在五行中显示前50个素数,每行10个
对问题进行如下的分解:
1, 判断一个数是不是素数
2, 针对2,3,4,5,6…测试它们是不是素数
3, 统计素数的个数
4, 打印每个素数每行显示10个
那么从上面的问题分解可以看出需要用到循环,并且在每判断出一个素数的情况下我们要对一个统计计数器进行加1至到这个计数器为50为止
publicclass PrimeNumber {
publicstaticvoid main(String[] args) {
finalint NUMBER_OF_PRIMES = 50; // 这个常量表示取前50个素数
finalint NUMBER_OF_PRIMES_PER_LINE = 10; // 这个常表示打印时每行显示多少个
int count = 0; // 这是一个统计过程中的计数器
int number = 2; // 这个表示计算素数从哪个数开始
System.out.println("前五十个素数如下:");
// 使用循环找出素数
while (count < NUMBER_OF_PRIMES) {
boolean isPrime = true; // 定义一个布尔变量表示经计算后这个数是否为素数
for (int divisor = 2; divisor <= number / 2; divisor++) {
if (number % divisor == 0) {
isPrime = false; // 表明不是素数
break; // 跳出内层循环
}
}
if (isPrime) {
count++;
if (count % NUMBER_OF_PRIMES_PER_LINE == 0)
System.out.println(number);
else
System.out.print(number + " ");
}
number++;
}
}
}
如下的程序使用确认对话框来控制循环
publicclass SentinelValueConfimationDialog {
publicstaticvoid main(String[] args) {
int sum = 0;
// 声明一个变量来使用得它为YES
int option = JOptionPane.YES_OPTION;
while (option == JOptionPane.YES_OPTION) {
String dataString = JOptionPane.showInputDialog("请输入一个整数:");
int data = Integer.parseInt(dataString);
sum += data;
// 这里对控制循环继续进行的变量进行赋值要求用户判断是否进行下去
option = JOptionPane.showConfirmDialog(null, "是否继续?");
}
// 在退出循环后对求和的结果显示出来
JOptionPane.showMessageDialog(null, "sum最后的值是" + sum, "结果",
JOptionPane.INFORMATION_MESSAGE);
}
}
在这个程序中先对这下确定的条件进行赋值然后再进行循环在完成循环要执行的动作后对确定循环条件再进行赋以相应的值!