Java编程技术与项目实战(第2版)
上QQ阅读APP看书,第一时间看更新

1.3 Java语言编程基础

Java语言同样遵循着严格的编程规范,Java的学习者必须了解Java语言的编程基础,遵循其编程规范,才能编写出好的Java程序。本节介绍的Java语法基础主要有Java的基本数据类型、标识符与关键字、运算符、控制语句与异常处理等。

1.3.1 Java基本数据类型

Java是一种强类型语言,它有着非常丰富的数据类型,可分为原始数据类型(基本数据类型)和构造数据类型(引用数据类型)两大类,其基本数据类型如表1.2所示。

表1.2 Java基本数据类型

000

说明:

Java语言的整型常量默认为int型,声明long型常量必须加小写“l”或大写“L”。

Java浮点型常量默认为double型,声明float型必须加小写“f”或大写“F”。

Java用Unicode码来表示字符,Unicode码定义了完全国际化的、可以表示所有人类语言已有的全部字符的字符集。

布尔型boolean主要用于逻辑测试。它只有两种可能的取值:true或false。

构造数据类型(引用数据类型)主要有数组、类、对象、接口等。

1.3.2 Java标识符与关键字

1. Java标识符

在Java语言中,用来标识类名、对象名、变量名、方法名、类型名、数组名、文件名的有效字符序列被称为“标识符”。简单地说,标识符就是一个名字。

Java标识符命名规则如下。

(1)标识符由字母、下划线“_”、美元符号“$”、数字组成。

(2)标识符由字母、下划线“_”、美元符号“$”开头。

(3)标识符大小写敏感,长度无限制。

参照表1.3中的例子理解体会上述命名的规则。

表1.3 Java标识符

000

2. Java关键字

关键字就是Java中赋以特定的含义,并用作专门用途的单词,不能作为一般的标识符。程序员在编写程序时,不能再使用这些词汇来命名标识符,也不能改变这些词汇的含义。这些专有词汇,称为“关键字”,如表1.4所示。注意所有Java关键字都是小写英文。

表1.4 Java关键字

000

说明:

数据和返回类型:int、void、return。

包/类/接口:package、class、interface。

修饰符:public、protected、private、final、abstract、static。

控制:continue、break、if、else、switch、case、default、do、for。

异常:try、catch、throw、throws、finally。

运算符:new、instanceof。

1.3.3 运算符

对于数据进行的操作称为运算,表示各种不同运算的符号称为运算符,参与运算的数据称为操作数。表达式是由操作数和运算符按一定的语法形式组成的有意义的符号序列。对表达式中的操作数进行运算得到的结果称为表达式的值,表达式值的数据类型即为表达式的类型。表达式的值还可以用作其他运算的操作数,形成更复杂的表达式。

Java语言中包括以下运算符。

单目算术运算符:+ +、- -、-。

双目算术运算符:+、-、*、/、%。

赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、>>=、>>>=、<<=、^=。

关系运算符:>、<、>=、<=、==、!= 。

逻辑运算符:&、&&、|、||、!、^。

位运算符:>>、<<、&、|、^、~。

条件运算符:? :。

成员运算符:. 。

下标运算符:[]。

实例类型判断运算符:instanceof 。

创建对象运算符:new。

强制类型转换运算符:(类型名称)。

1. 单目算术运算符

单目运算符的操作数只有一个,算术运算符中有3个单目运算符,如表1.5所示。

表1.5 单目算术运算符

000

2. 双目算术运算符

双目算术运算符如表1.6所示。

表1.6 双目算术运算符

000

3. 关系运算符

关系运算符是比较两个数据的大小关系的运算符,关系运算符的结果是布尔型,即true或false,如表1.7所示。

表1.7 关系运算符

000

4. 逻辑运算符

逻辑运算符是针对布尔型数据进行的运算,运算结果仍为布尔型量。常用的逻辑运算符如表1.8所示。

表1.8 逻辑运算符

000

这里要特别对逻辑运算进行进一步说明:Java提供了两个在其他大多数计算机语言中没有的有趣的布尔运算符。这就是逻辑与和逻辑或这两个运算符的特殊短路版本。例如,A && B、A || B。在逻辑或的运算中,如果第1个运算数A为真,则不管第2个运算数B是真是假,其运算结果都为真。同样,在逻辑与的运算中,如果第1个运算数A为假,则不管第2个运算数是真是假,其运算结果都为假。如果运用||和&&的形式,而不是|和&,那么一个运算数就能决定表达式的值,Java的短路版本就不会对第2个运算数求值,只有在需要时才对第2个运算数求值。为了完成正确的功能,当右边的运算数取决于左边的运算数是真还是假时,短路版本是很有用的。例如,下面的程序语句说明了短路逻辑运算符的优点,用它来防止被0除的错误:

if (count != 0 && num / count > 10) 

既然用了短路与运算符,就不会有当count为0时产生的意外运行错误。如果该行代码使用标准与运算符(&),则它将对两个运算数都求值,当出现被0除的情况时,就会产生运行错误。

5. 位运算符

位运算指的是对操作数以二进制为单位进行的运算,运算结果为整数。也就是说,将操作数转换为二进制表示形式,然后按位进行布尔运算,运算的结果也为二进制。位运算符及其运算规则如表1.9所示。

表1.9 位运算符

000

6. 赋值运算符

简单赋值运算符形式为“=”,Java中还提供了复合赋值运算符,其形式为“运算符<op>=”。复合赋值运算符的含义如表1.10所示。

表1.10 复合赋值运算符

000

7. 条件运算符

Java中唯一的一个三元运算符是“?:”,它有3个操作数。这种语法的作用与双分支的选择语句很相似,但其返回值更直接,书写形式更简洁。其语法形式如下:

逻辑表达式?表达式1:表达式2 

其中,逻辑表达式为boolean类型表达式,先计算逻辑表达式的值,若为true,则整个三目运算的结果为表达式1的值,否则整个运算结果为表达式2的值。

8. 运算符优先级

当一个表达式中有多个运算符参与混合运算时,表达式的运算次序取决于表达式中各种运算符的优先级,也就是说,不同的运算符有不同的优先级。Java运算符优先级如表1.11所示。

表1.11 运算符优先级

000

1.3.4 程序控制语句

Java语言中的程序流程控制语句有3种:顺序结构、选择结构和循环结构。Java的每条语句一般以分号(“;”)作为结束标志。

顺序结构:3种结构中最简单的一种,即语句按照书写的顺序依次执行。

选择结构:又称分支结构,将根据布尔值来判断应选择执行哪一个流程分支。

循环结构:在一定条件下反复执行一段语句的流程结构。

1. If-else选择语句

(1)简单的if选择语句

① if(条件表达式)。

语句              //只有一条语句 

② if(条件表达式)。

{ 
     一条或多条语句    //多条语句必须加大括号 
} 

(2)if-else双分支选择语句

① if(条件表达式)。

     语句1
else
     语句2

② if(条件表达式)。

{  
     语句块1  
}
else
{  
     语句块2  
}

(3)if-else-if多分支选择语句

if(条件表达式1) 
{   语句块1  } 
else  if(条件表达式2) 
{   语句块2  } 
… 
else  if(条件表达式n-1) 
{   语句块n-1  } 
else 
{    语句块n   } 

2. switch语句

当选择结构的分支越多时,if-else-if语句就会变得越来越难以看懂。Java提供了另一种多分支语句—switch语句。switch语句是多分支的开关语句。它的语法格式如下:

switch(表达式){
     case 常量表达式1:语句组1;
                               [break;]
     case 常量表达式2:语句组2;
                               [break;]
     case 常量表达式3:语句组3;
                               [break;]
     …
     case 常量表达式n-1:语句组n-1;
                               [break;]
     default:语句块n;
}

说明:

(1)switch后面的表达式的值的类型可以是char、byte、short、int型,但不能是boolean、long、float、double型。

(2)case后面的常量表达式的值的类型必须与switch后面的表达式的值的类型相匹配,而且必须是常量表达式或直接字面量。

(3)break语句可以省略,但省略时应注意,此时程序将按照顺序逐个执行switch中的每一条语句,直到遇到右大括号或者break语句为止。

(4)语句块可以是一条语句,也可以是多条语句,但此处的多条语句不需要使用大括号。

(5)case分支语句和default语句都不是必须的,也就是说它们在程序需要时是可以省略的。

3. while循环语句

while循环先判断条件后做循环。while循环语句的语法格式如下:

while(布尔表达式)
{   语句块 //循环体   }

说明:

(1)表达式必须是任何运算结果为布尔值的表达式。

(2)只有一条语句时可以省略大括号,但不建议这么做。

(3)while后面一定没有分号,在大括号后面也没有分号,这点初学者很容易忽略。

例1-1 使用while语句编写程序,求1000以内的所有偶数的和(包含1000)。

public class TestWhile{
  public static void main(String[] args){
     int i = 1, sum=0;
     while(i <= 1000){
          if(i%2==0)
               sum = sum + i;
          i++;
     } 
     System.out.println("1000之内所有偶数的和是:" + sum);
  }
}

4. do-while循环语句

与while语句功能相似的另一个循环语句是do-while语句。先做循环后判断条件。

do-while语句的语法格式如下:

do
{ 语句或语句块 //循环体 }
while(布尔表达式);

说明:

(1)表达式必须是任何计算结果为布尔值的表达式。

(2)只有一条语句时可以省略大括号,但不建议这么做。

(3)while后面一定要有分号,以表示do-while语句的结束。这一点与while语句不同。

例1-2 使用do-while语句编写程序,求1000以内的所有偶数的和(包含1000)。

public class TestDoWhile{
  public static void main(String[] args){
     int i = 1, sum=0;                             
     do{
          if(i%2==0)                               //判断i是否为偶数
               sum = sum + i;
          i++;
     } while(i <= 1000);
     System.out.println("1000之内所有偶数的和是:" + sum);
  }
}

5. for循环语句

在循环次数已知的情况下,可以使用for语句替代while或do-while语句。其语法格式如下:

for(初始化表达式;条件表达式;迭代式)
{  循环体语句  }

说明:

(1)初始化表达式通常用来对循环变量进行初始化,或者定义循环变量并初始化,在循环过程中只会被执行一次。

(2)条件表达式是一个布尔表达式,即运算结果为布尔值的表达式。只有当条件为true时才会执行。

(3)迭代表达式用于改变循环条件的语句,为继续执行循环体语句做准备。

(4)初始化循环变量可以在for语句之前声明,此时for语句中的初始化表达式就可以省略;循环变量的迭代式也可以在for循环体内执行,如for(;;){…}。

例1-3 使用for循环语句,求1000以内的所有偶数的和(包含1000)。

public class TestFor{
  public static void main(String[] args){
     int  sum=0;                           
     for(int i = 1;i <=1000;i++){
            if(i%2==0)                             //判断i是否为偶数
               sum = sum + i;
     } 
     System.out.println("1000之内所有偶数的和是:" + sum);
  }
}

6. 跳转语句

(1)break语句在前面讲过的switch语句、循环语句中,可以使用break语句来终止switch语句、循环语句的执行,而整个程序继续执行后面的语句。

(2)continue语句:continue语句的作用是提前结束本次循环,立即开始下一轮循环。

continue语句与break语句的区别:continue语句只结束本次循环,并不终止整个循环的执行;而break语句则是结束整个循环过程,不再判断循环的条件是否成立。

1.3.5 Java异常处理

异常是指程序在运行过程中出现由于硬件设备问题、软件设计错误等导致的程序异常事件,Java异常是一个描述在代码段中发生的异常情况的对象。

Java异常处理通过5个关键字控制:try、catch、throw、throws和finally。异常处理可以有以下几种。

(1)对运行时异常不做处理,由系统寻找处理的代码。

(2)使用try-catch-finally语句捕获异常。

(3)通过throws子句声明异常,还可自定义异常,用throw语句抛出。

1. try语句

为防止和处理一个运行时错误,只需要把你所要监控的代码放进一个try块就可以了。

例1-4 利用try语句捕获异常。

try{
     int n;
     n = new classTest.method();
     int[] array = new int[10];
     for (int i=0; i<n ; i++){
        array[i] =i ;                                         //可能引起数组越界异常
      }
}

try语句可以被嵌套。一个try语句可以在另一个try块内部。每次进入try语句,异常的前后关系都会入堆栈。如果一个内部的try语句不含特殊异常的catch处理程序,堆栈将弹出,下一个try语句的catch处理程序将检查是否与之匹配。这个过程将继续直到一个catch语句匹配成功,或者是直到所有的嵌套try语句被检查耗尽。如果没有catch语句匹配,Java运行时系统将处理这个异常。

2. catch语句

紧跟着try块的,包括一个说明你希望捕获的错误类型的catch子句。catch语句和try语句一起构成异常测试和捕获处理代码形式。

try-catch异常处理代码块的基本形式:
try{
          //监视可能发生异常的代码块
}
catch(异常类型异常对象名)  //捕获并处理异常
{   
          //异常处理代码块
}

改写上面的程序,包含一个因为被零除而产生的ArithmeticException异常的try块和一个catch子句。

例1-5 利用try-catch语句捕获ArithmeticException异常。

Public class Test
{ 
        public static void main(String args[]) 
        { 
               int a, b; 
               try 
               { 
                    a = 0; 
                    b= 5 / a; 
                    System.out.println("This will not be printed."); 
               } 
               catch (ArithmeticException e) 
               { 
                       System.out.println("Division by zero."); 
               } 
         System.out.println("After catch statement."); 
     } 
} 

该程序输出如下:

Division by zero. 
After catch statement. 

某些情况,由单个代码段可能引起多个异常。处理这种情况,可以定义两个或更多的catch子句,每个子句捕获一种类型的异常。当异常被引发时,每一个catch子句被依次检查,第一个匹配异常类型的子句被执行。当一个catch语句执行以后,其他的子句被旁路,执行从try-catch块以后的代码开始继续。多个catch异常处理代码块的基本形式:

try{
     //可能发生异常的代码块
}catch(异常类型1异常对象名1){
     //异常处理代码块1
}
…
catch(异常类型n异常对象名n){
     //异常处理代码块n;
}

3. finally语句

finally关键字是Java异常处理的最后一个语句,无论try语句中是否出现异常、出现哪种类型异常,finally关键字中包含的语句都必须被执行。如果异常被引发,finally甚至是在没有与该异常相匹配的catch子句的情况下也将执行。finally子句是可选项,可以有也可以无。然而每一个try语句至少需要一个catch或finally子句。

下面的例子显示了3种不同的退出方法,每一个都执行了finally子句。

例1-6 利用try-finally捕获异常。

class FinallyDemoTest 
{ 
       static void procA() 
     { 
     try 
     { 
     System.out.println("inside procA"); 
     throw new RuntimeException("demo"); 
     } 
     finally 
     { 
     System.out.println("procA's finally"); 
          } 
     } 
     static void procB() 
     { 
     try 
     { 
               System.out.println("inside procB"); 
               return; 
     } 
     finally 
     { 
               System.out.println("procB's finally"); 
     } 
} 
static void procC() 
{ 
     try 
     { 
          System.out.println("inside procC"); 
     } 
     finally 
     { 
          System.out.println("procC's finally"); 
     } 
    }
public static void main(String args[]) 
{ 
     try 
     { 
          procA(); 
     } 
     catch (Exception e) 
     { 
          System.out.println("Exception caught"); 
          } 
          procB(); 
          procC(); 
     } 
} 

procA()中finally子句在退出时执行。procB()中返回之前finally子句执行。procC()中没有错误,但finally块仍将执行。

下面是上述程序的输出结果:

inside procA 
procA's finally 
Exception caught 
inside procB 
procB's finally 
inside procC 
procC's finally