流程控制

用户交互Scanner

1、Scanner对象

之前我们学的基本语法中我们并没有实现程序和人的交互,但是Java给我们提供了这样一个工具类,我们可以获取用户的输入。java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入。

下面是创建 Scanner 对象的基本语法:

  1. Scanner s = new Scanner(System.in);

接下来我们演示一个最简单的数据输入,并通过 Scanner 类的 next()nextLine()方法获取输入的字符串,在读取前我们一般需要 使用 hasNext()hasNextLine() 判断是否还有输入的数据。

2、next & nextLine

我们使用next方式接收一下输入的数据!

  1. public static void main(String[] args) {
  2. //创建一个扫描器对象,用于接收键盘数据
  3. Scanner scanner = new Scanner(System.in);
  4. //next方式接收字符串
  5. System.out.println("Next方式接收:");
  6. //判断用户还有没有输入字符
  7. if (scanner.hasNext()){
  8. String str = scanner.next();
  9. System.out.println("输入内容:"+str);
  10. }
  11. //凡是属于IO流的类如果不关闭会一直占用资源.要养成好习惯用完就关掉.就好像你接水完了要关水龙头一样.很多下载软件或者视频软件如果你不彻底关,都会自己上传下载从而占用资源,你就会觉得
  12. 卡,这一个道理.
  13. scanner.close();
  14. }

测试数据:Hello World!
结果:只输出了Hello。

接下来我们使用另一个方法来接收数据:nextLine()

  1. public static void main(String[] args) {
  2. Scanner scan = new Scanner(System.in);
  3. // 从键盘接收数据
  4. // nextLine方式接收字符串
  5. System.out.println("nextLine方式接收:");
  6. // 判断是否还有输入
  7. if (scan.hasNextLine()) {
  8. String str2 = scan.nextLine();
  9. System.out.println("输入内容:" + str2);
  10. }
  11. scan.close();
  12. }

测试数据:Hello World!
结果:输出了Hello World!

两者区别:
next():

  • 1、一定要读取到有效字符后才可以结束输入。
  • 2、对输入有效字符之前遇到的空白,next()方法会自动将其去掉。
  • 3、只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
  • 4、next()不能得到带有空格的字符串。

nextLine():

  • 1、以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
  • 2、可以获得空白。

3、其他方法

如果要输入 int 或 float 类型的数据,在 Scanner 类中也有支持,但是在输入之前最好先使用hasNextXxx()方法进行验证,再使用 nextXxx()来读取:

【演示:IDEA中查看源码中的所有方法,并写出案例】

  1. public static void main(String[] args) {
  2. Scanner scan = new Scanner(System.in);
  3. // 从键盘接收数据
  4. int i = 0;
  5. float f = 0.0f;
  6. System.out.print("输入整数:");
  7. if (scan.hasNextInt()) {
  8. // 判断输入的是否是整数
  9. i = scan.nextInt();
  10. // 接收整数
  11. System.out.println("整数数据:" + i);
  12. } else {
  13. // 输入错误的信息
  14. System.out.println("输入的不是整数!");
  15. }
  16. System.out.print("输入小数:");
  17. if (scan.hasNextFloat()) {
  18. // 判断输入的是否是小数
  19. f = scan.nextFloat();
  20. // 接收小数
  21. System.out.println("小数数据:" + f);
  22. } else {
  23. // 输入错误的信息
  24. System.out.println("输入的不是小数!");
  25. }
  26. scan.close();
  27. }

以下实例我们可以输入多个数字,并求其总和与平均数,每输入一个数字用回车确认,通过输入非数字来结束输入并输出执行结果:

  1. public static void main(String[] args) {
  2. //扫描器接收键盘数据
  3. Scanner scan = new Scanner(System.in);
  4. double sum = 0; //和
  5. int m = 0; //输入了多少个数字
  6. //通过循环判断是否还有输入,并在里面对每一次进行求和和统计
  7. while (scan.hasNextDouble()) {
  8. double x = scan.nextDouble();
  9. m = m + 1;
  10. sum = sum + x;
  11. }
  12. System.out.println(m + "个数的和为" + sum);
  13. System.out.println(m + "个数的平均值是" + (sum / m));
  14. scan.close();
  15. }

Java中的流程控制语句分类:

  • 顺序结构
  • 选择结构
  • 循环结构

顺序结构

JAVA的基本结构就是顺序结构,除非特别指明,否则就按照顺序一句一句执行。顺序结构是最简单的算法结构。
image.png

语句与语句之间,框与框之间是按从上到下的顺序进行的,它是由若干个依次执行的处理步骤组成的,它是任何一个算法都离不开的一种基本算法结构。
顺序结构在程序流程图中的体现就是用流程线将程序框自上而地连接起来,按顺序执行算法步骤。

【演示】

  1. public static void main(String[] args) {
  2. System.out.println("Hello1");
  3. System.out.println("Hello2");
  4. System.out.println("Hello3");
  5. System.out.println("Hello4");
  6. System.out.println("Hello5");
  7. }
  8. //按照自上而下的顺序执行!依次输出。

选择结构

1、if单选择结构

我们很多时候需要去判断一个东西是否可行,然后我们才去执行,这样一个过程在程序中用if语句来表示:

image.png

  1. if(布尔表达式){
  2. //如果布尔表达式为true将执行的语句
  3. }

意义:if语句对条件表达式进行一次测试,若测试为真,则执行下面的语句,否则跳过该语句。

【演示】比如我们来接收一个用户输入,判断输入的是否为Hello字符串:

  1. public static void main(String[] args) {
  2. Scanner scanner = new Scanner(System.in);
  3. //接收用户输入
  4. System.out.print("请输入内容:");
  5. String s = scanner.nextLine();
  6. if (s.equals("Hello")){
  7. System.out.println("输入的是:"+s);
  8. }
  9. System.out.println("End");
  10. scanner.close();
  11. }

equals方法是用来进行字符串的比较的,之后会详解,这里大家只需要知道他是用来比较字符串是否一致的即可!和==是有区别的。】

2、if双选择结构

那现在有个需求,公司要收购一个软件,成功了,给人支付100万元,失败了,自己找人开发。这样的需求用一个if就搞不定了,我们需要有两个判断,需要一个双选择结构,所以就有了if-else结构。
image.png

  1. if(布尔表达式){
  2. //如果布尔表达式的值为true
  3. }else{
  4. //如果布尔表达式的值为false
  5. }

意义:当条件表达式为真时,执行语句块1,否则,执行语句块2。也就是else部分。

【演示】我们来写一个示例:考试分数大于60就是及格,小于60分就不及格。

  1. public static void main(String[] args) {
  2. Scanner scanner = new Scanner(System.in);
  3. System.out.print("请输入成绩:");
  4. int score = scanner.nextInt();
  5. if (score>60){
  6. System.out.println("及格");
  7. }else {
  8. System.out.println("不及格");
  9. }
  10. scanner.close();
  11. }

3、if多选择结构

我们发现上面的示例不符合实际情况,真实的情况还可能存在ABCD,存在区间多级判断。比如90-100就是A,80-90 就是B..等等,在生活中我们很多时候的选择也不仅仅只有两个,所以我们需要一个多选择结构来处理这类问题!
image.png

  1. if(布尔表达式 1){
  2. //如果布尔表达式 1的值为true执行代码
  3. }else if(布尔表达式 2){
  4. //如果布尔表达式 2的值为true执行代码
  5. }else if(布尔表达式 3){
  6. //如果布尔表达式 3的值为true执行代码
  7. }else {
  8. //如果以上布尔表达式都不为true执行代码
  9. }

if 语句后面可以跟 else if…else 语句,这种语句可以检测到多种可能的情况。

使用if,else if,else 语句的时候,需要注意下面几点:

  • if 语句至多有 1 个 else 语句,else 语句在所有的 else if 语句之后。
  • if 语句可以有若干个 else if 语句,它们必须在 else 语句之前。
  • 一旦其中一个 else if 语句检测为 true,其他的 else if 以及 else 语句都将跳过执行。

【演示】我们来改造一下上面的成绩案例,学校根据分数区间分为ABCD四个等级!

  1. public static void main(String[] args) {
  2. Scanner scanner = new Scanner(System.in);
  3. System.out.print("请输入成绩:");
  4. int score = scanner.nextInt();
  5. if (score==100){
  6. System.out.println("恭喜满分");
  7. }else if (score<100 && score >=90){
  8. System.out.println("A级");
  9. }else if (score<90 && score >=80){
  10. System.out.println("B级");
  11. }else if (score<80 && score >=70){
  12. System.out.println("C级");
  13. }else if (score<70 && score >=60){
  14. System.out.println("D级");
  15. }else if (score<60 && score >=0){
  16. System.out.println("不及格!");
  17. }else {
  18. System.out.println("成绩输入不合法!");
  19. }
  20. scanner.close();
  21. }

4、嵌套的if结构

使用嵌套的 if…else 语句是合法的。也就是说你可以在另一个 if 或者 else if 语句中使用 if 或者 else if 语句。你可以像 if 语句一样嵌套 else if...else

  1. if(布尔表达式 1){
  2. ////如果布尔表达式 1的值为true执行代码
  3. if(布尔表达式 2){
  4. ////如果布尔表达式 2的值为true执行代码
  5. }
  6. }

有时候我们在解决某些问题的时候,需要缩小查找范围,需要有层级条件判断,提高效率。
比如:我们需要寻找一个数,在1-100之间,我们不知道这个数是多少的情况下,我们最笨的方式就是一个个去对比,看他到底是多少,这会花掉你大量的时间,如果可以利用if嵌套比较,我们可以节省大量的成本。

5、switch多选择结构

多选择结构还有一个实现方式就是switch case语句
switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。

  1. switch(expression){
  2. case value :
  3. //语句
  4. break; //可选
  5. case value :
  6. //语句
  7. break; //可选
  8. //你可以有任意数量的case语句
  9. default : //可选
  10. //语句
  11. }

switch case 语句有如下规则

  • switch 语句中的变量类型可以是: byte、short、int 或者 char。从 Java SE 7 开始,switch 支持
  • 字符串 String 类型了,同时 case 标签必须为字符串常量或字面量。
  • switch 语句可以拥有多个 case 语句。每个 case 后面跟一个要比较的值和冒号。
  • case 语句中的值的数据类型必须与变量的数据类型相同,而且只能是常量或者字面常量。
  • 当变量的值与 case 语句的值相等时,那么 case 语句之后的语句开始执行,直到 break 语句出现才会跳出 switch 语句。
  • 当遇到 break 语句时,switch 语句终止。程序跳转到 switch 语句后面的语句执行。case 语句不必须要包含 break 语句。如果没有 break 语句出现,程序会继续执行下一条 case 语句,直到出现break 语句。
  • switch 语句可以包含一个 default 分支,该分支一般是 switch 语句的最后一个分支(可以在任何位置,但建议在最后一个)。default 在没有 case 语句的值和变量值相等的时候执行。default 分支不需要 break 语句。

switch case 执行时,一定会先进行匹配,匹配成功返回当前 case 的值,再根据是否有 break,判断是否继续输出,或是跳出判断。

  1. public static void main(String args[]){
  2. //char grade = args[0].charAt(0);
  3. char grade = 'C';
  4. switch(grade)
  5. {
  6. case 'A' :
  7. System.out.println("优秀");
  8. break;
  9. case 'B' :
  10. case 'C' :
  11. System.out.println("良好");
  12. break;
  13. case 'D' :
  14. System.out.println("及格");
  15. break;
  16. case 'F' :
  17. System.out.println("你需要再努力努力");
  18. break;
  19. default :
  20. System.out.println("未知等级");
  21. }
  22. System.out.println("你的等级是 " + grade);
  23. }

如果 case 语句块中没有 break 语句时,匹配成功后,从当前 case 开始,后续所有 case 的值都会输出。如果后续的 case 语句块有 break 语句则会跳出判断。【case穿透】

  1. public static void main(String args[]){
  2. int i = 1;
  3. switch(i){
  4. case 0:
  5. System.out.println("0");
  6. case 1:
  7. System.out.println("1");
  8. case 2:
  9. System.out.println("2");
  10. case 3:
  11. System.out.println("3");
  12. break;
  13. default:
  14. System.out.println("default");
  15. }
  16. }

输出:1,2,3。

【JDK7增加了字符串表达式】

  1. public static void main(String[] args) {
  2. String name = "狂神";
  3. switch (name) { //JDK7的新特性,表达式结果可以是字符串!!!
  4. case "秦疆":
  5. System.out.println("输入的秦疆");
  6. break;
  7. case "狂神":
  8. System.out.println("输入的狂神");
  9. break;
  10. default:
  11. System.out.println("弄啥嘞!");
  12. break;
  13. }
  14. }

循环结构

顺序结构的程序语句只能被执行一次。如果您想要同样的操作执行多次,,就需要使用循环结构。
Java中有三种主要的循环结构:

  • while 循环
  • do…while 循环
  • for循环

在Java5中引入了一种主要用于数组的增强型for循环。

1、while 循环

while是最基本的循环,它的结构为:

  1. while( 布尔表达式 ) {
  2. //循环内容
  3. }

只要布尔表达式为 true,循环就会一直执行下去。
image.png

【图解】在循环刚开始时,会计算一次“布尔表达式”的值,若条件为真,执行循环体。而对于后来每一次额外的循环,都会在开始前重新计算一次判断是否为真。直到条件不成立,则循环结束。

我们大多数情况是会让循环停止下来的,我们需要一个让表达式失效的方式来结束循环。
方式有:循环内部控制,外部设立标志位等。

  1. public static void main(String[] args) {
  2. int i = 0;
  3. //i小于100就会一直循环
  4. while (i<100){
  5. i++;
  6. System.out.println(i);
  7. }
  8. }

少部分情况需要循环一直执行,比如服务器的请求响应监听等。

  1. public static void main(String[] args) {
  2. while (true){
  3. //等待客户端连接
  4. //定时检查
  5. //......
  6. }
  7. }

循环条件一直为true就会造成无限循环【死循环】,我们正常的业务编程中应该尽量避免死循环。会影响程序性能或者造成程序卡死奔溃!

【案例:计算1+2+3+…+100=?】

  1. public static void main(String[] args) {
  2. int i = 0;
  3. int sum = 0;
  4. while (i <= 100) {
  5. sum = sum+i;
  6. i++;
  7. }
  8. System.out.println("Sum= " + sum);
  9. }

【科普:高斯的故事】
德国大数学家高斯(Gauss):高斯是一对普通夫妇的儿子.他的母亲是一个贫穷石匠的女儿,虽然十分聪明,但却没有接受过教育,近似于文盲.在她成为高斯父亲的第二个妻子之前,她从事女佣工作.他的父亲曾做过园丁,工头,商人的助手和一个小保险公司的评估师.当高斯三岁时便能够纠正他父亲的借债账目的事情,已经成为一个轶事流传至今.他曾说,他在麦仙翁堆上学会计算.能够在头脑中进行复杂的计算,是上帝赐予他一生的天赋.

高斯用很短的时间计算出了小学老师布置的任务:对自然数从1到100的求和.他所使用的方法是:对50对构造成和101的数列求和(1+100,2+99,3+98……),同时得到结果:5050.这一年,高斯9岁.

2、do…while 循环

对于 while 语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次。do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。

  1. do {
  2. //代码语句
  3. }while(布尔表达式);

image.png
注意:布尔表达式在循环体的后面,所以语句块在检测布尔表达式之前已经执行了。 如果布尔表达式的值为 true,则语句块一直执行,直到布尔表达式的值为 false。

我们用do…while改造一下上面的案例!

  1. public static void main(String[] args) {
  2. int i = 0;
  3. int sum = 0;
  4. do {
  5. sum = sum+i;
  6. i++;
  7. }while (i <= 100);
  8. System.out.println("Sum= " + sum);
  9. }

执行结果当然是一样的!

While和do-While的区别:

  • while先判断后执行。dowhile是先执行后判断!
  • Do…while总是保证循环体会被至少执行一次!这是他们的主要差别。
  1. public static void main(String[] args) {
  2. int a = 0;
  3. while(a<0){
  4. System.out.println(a);
  5. a++;
  6. }
  7. System.out.println("-----");
  8. do{
  9. System.out.println(a);
  10. a++;
  11. } while (a<0);
  12. }

3、For 循环

虽然所有循环结构都可以用 while 或者 do…while表示,但 Java 提供了另一种语句 —— for 循环,使一些循环结构变得更加简单。

  • for循环语句是支持迭代的一种通用结构,是最有效、最灵活的循环结构。
  • for循环执行的次数是在执行前就确定的。

语法格式如下:

  1. for(初始化; 布尔表达式; 更新) {
  2. //代码语句
  3. }

image.png
关于 for 循环有以下几点说明:

  • 最先执行初始化步骤。可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。
  • 然后,检测布尔表达式的值。如果为 true,循环体被执行。如果为false,循环终止,开始执行循环体后面的语句。
  • 执行一次循环后,更新循环控制变量(迭代因子控制循环变量的增减)。
  • 再次检测布尔表达式。循环执行上面的过程。

【演示:while和for输出】

  1. public static void main(String[] args) {
  2. int a = 1; //初始化
  3. while(a<=100){ //条件判断
  4. System.out.println(a); //循环体
  5. a+=2; //迭代
  6. }
  7. System.out.println("while循环结束!");
  8. for(int i = 1;i<=100;i++){ //初始化//条件判断 //迭代
  9. System.out.println(i); //循环体
  10. }
  11. System.out.println("while循环结束!");
  12. }

我们发现,for循环在知道循环次数的情况下,简化了代码,提高了可读性。

4、练习

【练习1:计算0到100之间的奇数和偶数的和】

  1. public static void main(String[] args) {
  2. int oddSum = 0; //用来保存奇数的和
  3. int evenSum = 0; //用来存放偶数的和
  4. for(int i=0;i<=100;i++){
  5. if(i%2!=0){
  6. oddSum += i;
  7. }else{
  8. evenSum += i;
  9. }
  10. }
  11. System.out.println("奇数的和:"+oddSum);
  12. System.out.println("偶数的和:"+evenSum);
  13. }

【练习2:用while或for循环输出1-1000之间能被5整除的数,并且每行输出3个】

  1. public static void main(String[] args) {
  2. for(int j = 1;j<=1000;j++){
  3. if(j%5==0){
  4. System.out.print(j+"\t");
  5. }
  6. if(j%(5*3)==0){
  7. System.out.println();
  8. }
  9. }
  10. }

【练习3:打印九九乘法表】

  1. 1*1=1
  2. 1*2=2 2*2=4
  3. 1*3=3 2*3=6 3*3=9
  4. 1*4=4 2*4=8 3*4=12 4*4=16
  5. 1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
  6. 1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
  7. 1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
  8. 1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
  9. 1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72
  10. 9*9=81

我们使用嵌套for循环就可以很轻松解决这个问题了!

第一步:我们先打印第一列,这个大家应该都会

  1. for (int i = 1; i <= 9; i++) {
  2. System.out.println(1 + "*" + i + "=" + (1 * i));
  3. }

第二步:我们把固定的1再用一个循环包起来

  1. for (int i = 1; i <= 9 ; i++) {
  2. for (int j = 1; j <= 9; j++) {
  3. System.out.println(i + "*" + j + "=" + (i * j));
  4. }
  5. }

第三步:去掉重复项,j<=i

  1. for (int i = 1; i <= 9 ; i++) {
  2. for (int j = 1; j <= i; j++) {
  3. System.out.println(j + "*" + i + "=" + (i * j));
  4. }
  5. }

第四步:调整样式

  1. for (int i = 1; i <= 9 ; i++) {
  2. for (int j = 1; j <= i; j++) {
  3. System.out.print(j + "*" + i + "=" + (i * j)+ "\t");
  4. }
  5. System.out.println();
  6. }

5、增强for循环

Java5 引入了一种主要用于数组或集合的增强型 for 循环。

Java 增强 for 循环语法格式如下:

  1. for(声明语句 : 表达式)
  2. {
  3. //代码句子
  4. }

声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。
表达式:表达式是要访问的数组名,或者是返回值为数组的方法。

【演示:增强for循环遍历输出数组元素】

  1. public static void main(String[] args) {
  2. int [] numbers = {10, 20, 30, 40, 50};
  3. for(int x : numbers ){
  4. System.out.print( x );
  5. System.out.print(",");
  6. }
  7. System.out.print("\n");
  8. String [] names ={"James", "Larry", "Tom", "Lacy"};
  9. for( String name : names ) {
  10. System.out.print( name );
  11. System.out.print(",");
  12. }
  13. }

break & continue

1、break 关键字

  • break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。
  • break 跳出最里层的循环,并且继续执行该循环下面的语句。

【演示:跳出循环】

  1. public static void main(String[] args) {
  2. int i=0;
  3. while (i<100){
  4. i++;
  5. System.out.println(i);
  6. if (i==30){
  7. break;
  8. }
  9. }
  10. }

switch 语句中break在上面已经详细说明了,如果有疑惑可以回头看switch多选择结构小节;

2、continue 关键字

  • continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。
  • 在 for 循环中,continue 语句使程序立即跳转到更新语句。
  • 在 while 或者 do…while 循环中,程序立即跳转到布尔表达式的判断语句。

【演示】

  1. public static void main(String[] args) {
  2. int i=0;
  3. while (i<100){
  4. i++;
  5. if (i%10==0){
  6. System.out.println();
  7. continue;
  8. }
  9. System.out.print(i);
  10. }
  11. }

3、两者区别

  • break
    • break在任何循环语句的主体部分,均可用break控制循环的流程。
    • break用于强行退出循环,不执行循环中剩余的语句。(break语句也在switch语句中使用)
  • continue
    • continue 语句用在循环语句体中,用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。

4、带标签的continue

【了解即可】

  1. goto关键字很早就在程序设计语言中出现。尽管goto仍是Java的一个保留字,但并未在语言中得到正式使用;Java没有goto。然而,在break和continue这两个关键字的身上,我们仍然能看出一些goto的影子—-带标签的break和continue。
  2. “标签”是指后面跟一个冒号的标识符,例如:label:
  3. 对Java来说唯一用到标签的地方是在循环语句之前。而在循环之前设置标签的唯一理由是:我们希望在其中嵌套另一个循环,由于break和continue关键字通常只中断当前循环,但若随同标签使用,它们就会中断到存在标签的地方。
  4. 带标签的break和continue的例子:

【演示:打印101-150之间所有的质数】

  1. public static void main(String[] args) {
  2. int count = 0;
  3. outer: for (int i = 101; i < 150; i ++) {
  4. for (int j = 2; j < i / 2; j++) {
  5. if (i % j == 0)
  6. continue outer;
  7. }
  8. System.out.print(i+ " ");
  9. }
  10. }

方法

1、何谓方法?

在前面几个章节中我们经常使用到 System.out.println(),那么它是什么呢?

  • println() 是一个方法。
  • System 是系统类。
  • out是标准输出对象。

这句话的用法是调用系统类 System 中的标准输出对象 out 中的方法 println()

那么什么是方法呢?
Java方法是语句的集合,它们在一起执行一个功能。

  • 方法是解决一类问题的步骤的有序组合
  • 方法包含于类或对象中
  • 方法在程序中被创建,在其他地方被引用

设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子性,就是一个方法只完成1个功能,这样利于我们后期的扩展。

方法的优点

  • 使程序变得更简短而清晰。
  • 有利于程序维护。
  • 可以提高程序开发的效率。
  • 提高了代码的重用性。

回顾:方法的命名规则?

2、方法的定义

Java的方法类似于其它语言的函数,是一段用来完成特定功能的代码片段,一般情况下,定义一个方法包含以下语法:

  1. 修饰符 返回值类型 方法名(参数类型 参数名){
  2. ...
  3. 方法体
  4. ...
  5. return 返回值;
  6. }

方法包含一个方法头和一个方法体。
下面是一个方法的所有部分:

  • 修饰符:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
  • 返回值类型 :方法可能会返回值。returnValueType是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType关键字void
  • 方法名:是方法的实际名称。方法名和参数表共同构成方法签名。
  • 参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
    • 形式参数:在方法被调用时用于接收外界输入的数据。
    • 实参:调用方法时实际传给方法的数据。
  • 方法体:方法体包含具体的语句,定义该方法的功能。

比如我们写一个比大小的方法:
【演示】下面的方法包含 2 个参数 num1 和 num2,它返回这两个参数的最大值。

  1. /** 返回两个整型变量数据的较大值 */
  2. public static int max(int num1, int num2) {
  3. int result;
  4. if (num1 > num2)
  5. result = num1;
  6. else
  7. result = num2;
  8. return result;
  9. }

【演示:加法】

  1. public int add(int num1, int num2) {
  2. return num1+num2;
  3. }

3、方法调用

Java 支持两种调用方法的方式,根据方法是否返回值来选择。

当程序调用一个方法时,程序的控制权交给了被调用的方法。当被调用方法的返回语句执行或者到达方法体闭括号时候交还控制权给程序。

当方法返回一个值的时候,方法调用通常被当做一个值。例如:

  1. int larger = max(30, 40);

Java语言中使用下述形式调用方法:对象名.方法名(实参列表)
如果方法返回值是void,方法调用一定是一条语句。例如,方法println返回void。
下面的调用是个语句:

  1. System.out.println("Hello,kuangshen!");

【演示:定义方法并且调用它】

  1. public static void main(String[] args) {
  2. int i = 5;
  3. int j = 2;
  4. int k = max(i, j);
  5. System.out.println( i + " 和 " + j + " 比较,最大值是:" + k);
  6. }
  7. /** 返回两个整数变量较大的值 */
  8. public static int max(int num1, int num2) {
  9. int result;
  10. if (num1 > num2)
  11. result = num1;
  12. else
  13. result = num2;
  14. return result;
  15. }

这个程序包含 main 方法max 方法。main 方法是被 JVM 调用的,除此之外,main 方法和其它方法没什么区别。JAVA中只有值传递!

main 方法的头部是不变的,如例子所示,带修饰符 public 和 static,返回 void 类型值,方法名字是main,此外带个一个 String[] 类型参数。String[] 表明参数是字符串数组。

4、方法的重载

上面使用的max方法仅仅适用于int型数据。但如果你想得到两个浮点类型数据的最大值呢?
解决方法是创建另一个有相同名字但参数不同的方法,如下面代码所示:

  1. public static double max(double num1, double num2) {
  2. if (num1 > num2)
  3. return num1;
  4. else
  5. return num2;
  6. }
  7. public static int max(int num1, int num2) {
  8. int result;
  9. if (num1 > num2)
  10. result = num1;
  11. else
  12. result = num2;
  13. return result;
  14. }
  • 如果你调用max方法时传递的是int型参数,则 int型参数的max方法就会被调用;
  • 如果传递的是double型参数,则double类型的max方法体会被调用,这叫做方法重载;
  • 就是说一个类的两个方法拥有相同的名字,但是有不同的参数列表。
  • Java编译器根据方法签名判断哪个方法应该被调用。
  • 方法重载可以让程序更清晰易读。执行密切相关任务的方法应该使用相同的名字。
  • 重载的方法必须拥有不同的参数列表。你不能仅仅依据修饰符或者返回类型的不同来重载方法。

5、拓展命令行传参

有时候你希望运行一个程序时候再传递给它消息。这要靠传递命令行参数给main()函数实现。
命令行参数是在执行程序时候紧跟在程序名字后面的信息。

【下面的程序打印所有的命令行参数】

  1. public class CommandLine {
  2. public static void main(String args[]){
  3. for(int i=0; i<args.length; i++){
  4. System.out.println("args[" + i + "]: " + args[i]);
  5. }
  6. }
  7. }

【命令行】

  1. $ javac CommandLine.java
  2. $ java CommandLine this is a command line 200 -100
  3. args[0]: this
  4. args[1]: is
  5. args[2]: a
  6. args[3]: command
  7. args[4]: line
  8. args[5]: 200
  9. args[6]: -100

【错误: 找不到或无法加载主类,解决方法】
在项目输出的项目目录下执行java命令,写完整路径即可。

  1. $ java com.kuang.chapter3.Demo03 Hello World

6、可变参数

JDK 1.5 开始,Java支持传递同类型的可变参数给一个方法。

方法的可变参数的声明如下所示:

  1. typeName... parameterName

在方法声明中,在指定参数类型后加一个省略号(…) 。
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。

  1. public static void main(String args[]) {
  2. // 调用可变参数的方法
  3. printMax(34, 3, 3, 2, 56.5);
  4. printMax(new double[]{1, 2, 3});
  5. }
  6. public static void printMax( double... numbers) {
  7. if (numbers.length == 0) {
  8. System.out.println("No argument passed");
  9. return;
  10. }
  11. double result = numbers[0];
  12. //排序!
  13. for (int i = 1; i < numbers.length; i++){
  14. if (numbers[i] > result) {
  15. result = numbers[i];
  16. }
  17. }
  18. System.out.println("The max value is " + result);
  19. }

7、递归

A方法调用B方法,我们很容易理解!

递归就是:A方法调用A方法!就是自己调用自己,因此我们在设计递归算法时,一定要指明什么时候自己不调用自己。否则,就是个死循环!

递归算法重点:

  • 递归是一种常见的解决问题的方法,即把问题逐渐简单化。
  • 递归的基本思想就是“自己调用自己”,一个使用递归技术的方法将会直接或者间接的调用自己。
  • 利用递归可以用简单的程序来解决一些复杂的问题。它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。

递归结构包括两个部分:

  • 递归头。解答:什么时候不调用自身方法。如果没有头,将陷入死循环。
  • 递归体。解答:什么时候需要调用自身方法。

【演示:利用代码计算5的乘阶!】

  1. //5*4*3*2*1
  2. public static void main(String[] args) {
  3. System.out.println(f(5));
  4. }
  5. public static int f(int n) {
  6. if (1 == n)
  7. return 1;
  8. else
  9. return n*f(n-1);
  10. }

image.png

此题中,按照递归的三个条件来分析:
(1)边界条件:阶乘,乘到最后一个数,即1的时候,返回1,程序执行到底;
(2)递归前进段:当前的参数不等于1的时候,继续调用自身;
(3)递归返回段:从最大的数开始乘,如果当前参数是5,那么就是5 4,即5 (5-1),即n * (n-1)

递归其实是方便了程序员难为了机器,递归可以通过数学公式很方便的转换为程序。其优点就是易理解,容易编程。但递归是用栈机制实现的,每深入一层,都要占去一块栈数据区域,对嵌套层数深的一些算法,递归会力不从心,空间上会以内存崩溃而告终,而且递归也带来了大量的函数调用,这也有许多额外的时间开销。所以在深度大时,它的时空性就不好了。(会占用大量的内存空间)

而迭代虽然效率高,运行时间只因循环次数增加而增加,没什么额外开销,空间上也没有什么增加,但缺点就是不容易理解,编写复杂问题时困难。

能不用递归就不用递归,递归都可以用迭代来代替。

总结和作业

总结:

  • 用户交互Scanner
  • 顺序结构
  • 选择结构
  • 循环结构
  • break & continue
  • 方法

作业:
写一个计算器,要求实现加减乘除功能,并且能够循环接收新的数据,通过用户交互实现。思路推荐:

  1. 写4个方法:加减乘除
  2. 利用循环+switch进行用户交互
  3. 传递需要操作的两个数
  4. 输出结果