Java基础知识点复习3(编辑中)

来源https://course.tianmaying.com/java-basic+java-environment

十四、异常处理

异常定义了程序中遇到的非致命的错误,比如如程序要打开一个不存的文件、网络连接中断、除零操作、操作数越界、装载一个不存在的类等情况。

先来看看下面的程序代码:

package com.tianmaying;

public class HelloWorld {    
    public static void main(String[] args) {
        int x = 5 / 0;
        System.out.println(x);
    }
}
编译运行上面的程序,将出现如下错误:

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at com.tianmaying.HelloWorld.main(HelloWorld.java:5)
上面的程序运行的结果报告发生了算术异常( ArithMethicException),应用执行提前结束,这种情况就是我们所说的异常。

Java异常强制我们去考虑程序的强健性和安全性,其在设计时就考虑到这些问题,提出了一套异常处理的解决方案。将上面的程序代码进行如下修改:

package com.tianmaying;

public class HelloWorld {    
    public static void main(String[] args) {
        try {
            int x = 5 / 0;
            System.out.println(x);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("program is still running here!");
    }
}

程序运行结果如下:

java.lang.ArithmeticException: / by zero
	at com.tianmaying.HelloWorld.main(HelloWorld.java:6)
program is still running here!

我们将可能出现异常的代码通过try/catch代码进行了处理,当异常发生时,系统能够继续运行,而没有意外终止。

try代码块中的语句发生了异常,程序就会跳转到catch代码块中执行,执行完catch代码块中的程序代码后,系统会继续执行catch代码块之后的代码,try代码块中发生异常语句后的代码则不会再执行。比如如程序中的System.out.println(x);不会再被执行。

异常发生时,系统会将代码行号,异常类别等信息封装到一个对象中,并将这个对象传递给catch代码块,catch代码块是以下面的格式出现的。

catch关键字后跟有一个用括号括起来的Exception类型的参数e,这跟我们经常用到的如何定义一个函数接收的参数格式是一样的。

括号中的Exception就是try代码块传递给catch代码块的变量类型,e就是变量名,所以我们也可以将e改用成别的名称(如ex),如下所

每个try语句必须有一个或多个catch语句对应,try代码块与catch代码块代码块之间不能有其他语句。

十五、Java IO

Java IO 是一套Java用来读写数据(输入和输出)的API。大部分程序都要处理一些输入,并由输入产生一些输出。Java为此提供了java.io包,主要涉及文件,网络数据流,内存缓冲等的输入输出。

Java IO中的一个核心概念是(Stream),从外部(包括磁盘文件、键盘、网络套接字)读入到内存中的数据序列称为输入流,从内存写入到外部设备的数据序列称为输出流

流中的数据既可以是未经加工的原始二进制数据,也可以是经一定编码处理后符合某种格式规定的特定数据。因此Java中的流分为两种:

  • 字节流:数据流中最小的数据单元是字节,多用于读取或书写二进制数据
  • 字符流:数据流中最小的数据单元是字符, Java中的字符是Unicode编码,一个字符占用两个字节

字节流:

字节流的最顶层是两个抽象类: InputStreamOutputStream,其他关于处理字节的类都是它们的子类,这些子类对不同的外设进行处理,例如磁盘文件,网络连接,甚至是内存缓冲区。

抽象类InputStreamOutputStream中定义两个关键的抽象方法read()write(),它们分别对数据的字节进行读写,其子类重载完成特定输入输出方式的对应实现。

下面的代码通过FileInoutStreamFileOutputStream来完成文件内容的拷贝:

package com.tianmaying;
import java.io.*;

public class CopyFileByte {
   public static void main(String args[]) throws IOException
   {
      FileInputStream in = null;
      FileOutputStream out = null;
      try {
         in = new FileInputStream("input.txt");
         out = new FileOutputStream("output.txt");         
         int c;
         while ((c = in.read()) != -1) { // 返回-1 表示达到文件结尾
            out.write(c);
         }
      }finally {
         if (in != null) {
           in.close();
        }
         if (out != null) {
            out.close();
         }
      } 
   }
}

字节流的每次操作都是一个数据单位—— 字节。假如input.txt文件中包含“Hello world”,那么它将复制完'H'之后,再复制'e',接下来复制'l',直到其结束。 in.read()每次从输入流中读取一个字节,如果达到文件末尾就返回 -1。注意使用完输入输出流,一定调用 close()方法将其关闭。

字符流

Java 字符流用于处理16位 unicode 的输入和输出。字符流的两个顶层抽象类是ReaderWriter,分别定义了关键方法read()write(),表示对字符的读写。

用字符流的方式进行文件内容拷贝的代码如下:

package com.tianmaying;
import java.io.*;

public class CopyFileCharacter {
   public static void main(String args[]) throws IOException
   {
      FileReader in = null;
      FileWriter out = null;
      try {
         in = new FileReader("input.txt");
         out = new FileWriter("output.txt");

         int c;
         while ((c = in.read()) != -1) {
            out.write(c);
         }
      }finally {
         if (in != null) {
            in.close();
         }
         if (out != null) {
            out.close();
         }
      }
   }
}
这里使用的 FileReaderFileWriter,它们操作的最小单位是一个字符16 bits,而 FileInputStreamFileOutputStream最小单位则是一个字节8 bits.

所有的编程语言都提供了对标准 I/O 流的支持,即用户可以从键盘上进行输入,并且从控制台屏幕上输出。Java提供了以下的三种标准流:

  • Standard Input: 用以将数据输入给用户的程序,通常键盘作为标准输入流,表示为System.in,其类型是InputStream
  • Standard Output:用以输出用户程序产生的数据,通常控制台屏幕作为标准输出流,表示为 System.out,其类型是PrintStream
  • Standard Error: 这是用来输出用户产生的错误数据,通常控制台屏幕作为标准错误流,表示为 System.err,类型和System.out相同是PrintStream
下面的程序通过创建一个 InputStreamReader来读标准输入流直到用户输入字符 "q":

package com.tianmaying;
import java.io.*;

class ConsoleInOut {
    public static void main(String args[])throws IOException{
      InputStreamReader isr = null;
      try {
         isr = new InputStreamReader(System.in);
         System.out.println("Enter characters, 'q' to quit.");
         char c;
         do {
            c = (char) isr.read();
            System.out.println(c);
         } while(c != 'q');
      }finally {
         if (isr != null) {
            isr.close();
         }
      }
    }
}
如果我们在控制台中输入 tianmaying!,则控制台的输入如下
Enter characters, 'q' to quit.
tianmaying!
t
i
a
n
m
a
y
i
n
g
!

q
从控制台读入单个字符我们用了 read()方法,读入字符串则可以使用 readLine()方法,该方法返回的是 String类型的字符串对象。

回顾我们已经学习过的Scanner,创建Scanner对象时需要用System.in作为它的参数, ScannerSystem.in取得用户输入的内容后,进一步提供了更易于我们调用的方法,如:

  • next():取得一个字符串
  • hasNext():是否还有输入
  • nextInt():将取得的字符串转换成int类型的整数
  • nextFloat():将取得的字符串转换成float
  • nextBoolean():将取得的字符串转换成boolean

使用Scanner非常方便,但也有不足。Scanner取得输入的依据是空格符,包括空格键、Tab键和回车键等。当按下这些键时,Scanner就会返回下一个输入。因此当你输入的内容中间包括空格时,显然使用Scanner不能完整的获得你输入的字符串。

文件处理最常用的两个流是FileInputStreamFileOutputStream

对于FileInputStream,可以以文件名的字符串为参数来创建一个输入流对象去读文件:

InputStream f = new FileInputStream("D:/java");
也可以以一个文件对象作为参数来去创建一个输入流对象去读文件,首先我们需要创建一个 File文件对象。

File f = new File("D:/java");
InputStream f = new FileInputStream(f);
对于 FileOutputStream类似。

package com.tianmaying;
import java.io.*;

public class fileStreamTest{

   public static void main(String args[]){

	   try{
	      byte bWrite [] = {10,20,30,40,50};
	      OutputStream os = new FileOutputStream("test.txt");
	      for(int x = 0; x < bWrite.length ; x++){
	         os.write( bWrite[x] ); // writes the bytes
	      }
	      os.close();
	
	      InputStream is = new FileInputStream("test.txt");
	      int size = is.available();
	
	      for(int i = 0; i< size; i++){
	         System.out.print((char)is.read() + "  ");
	      }
	      is.close();
	   } catch(IOException e){
      System.out.print("IOException");
	   }    
   }
}
上一节中创建文件输入输出流时,我们用到了 File类。 File 类用于进行文件(以及目录)的相关操作,位于 java.io包中。对一个文件进行操作,可以创建一个 File对象:

File file = new File("input.txt"); //文件位于当前目录下
File file = new File("D:/java","input.txt"); //文件位于/home/user目录下


package com.tianmaying;
import java.io.*;

public class TestAbstract {  
    public static void main(String args[]) throws IOException {  
        File dir = new File("D:/java");  
        File file1 = new File(dir, "fileTest001.txt");  
        File file2 = new File(dir, "fileTest002.java");   
        
        if (!dir.exists())  
            dir.mkdir();  
        if (!file1.exists())  
            file1.createNewFile();  
        if (!file2.exists())  
            file2.createNewFile();  
            
        System.out.println("file1's AbsolutePath=  " + file1.getAbsolutePath());  
18        System.out.println("file2's AbsolutePath=  " + file2.getAbsolutePath());  
        
        System.out.println("file1 Canread=" + file1.canRead());  
        System.out.println("file1's len= " + file1.length());  
        
        String[] fileList = dir.list(); 
        System.out.println("there are " + fileList.length + " file(s) in D:/java");  
    }  

}
输出如下:

1file1's AbsolutePath=  D:\java\fileTest001.txt
file2's AbsolutePath=  D:\java\fileTest002.java
file1 Canread=true
file1's len= 0
there are 12 file(s) in D:/java

十二、反射

反射是一种动态获取信息以及动态调用对象方法的机制。在程序运行状态中,通过反射能够知道某个类具有哪些属性和方法;能够访问某一个对象的方法和属性。

具体来说,反射机制主要提供了以下功能:
•在运行时判断任意一个对象所属的类;
•在运行时构造任意一个类的对象;
•在运行时判断任意一个类所具有的成员变量和方法;
•在运行时调用任意一个对象的方法;
•生成动态代理。

任何一个类都有getClass()方法,调用该方法即可获得一个表示类信息的对象Class。
当然,我们获取Class并不仅仅是希望做类似getName()这样简单的操作,一般会进一步创建实例和访问方法属性等操作

通过反射可以获取一个类的父类以及它实现的接口:

你可能会说直接使用new操作创建对象不就行了吗? 试想如果你需要从一个文件里读入类的名字,然后根据这个名字来创建类,这个时候new操作就无能为力了,而上面代码中的方式就有用武之地了。

通过反射,不仅可以获取属性的名称,还能获取属性类型和修饰符,这些信息存储在Field对象中。

通过Field对象,可以改变对应属性的可见性,也可以通过set()方法进行属性的赋值:

通过反射,可以获取方法的整个签名信息,这些信息存储在Method对象中:

通过Method对象,也可以通过invoke()方法进行方法调用:

十七、日期处理

Java 8在java.time包中包含了一组全新的时间日期API

Clock类提供了访问当前日期和时间的方法。Clock是时区敏感的,可以用来取代System.cur

rentTimeMillis() 来获取代表当前时间的微秒数。某一个特定的时间点也可以使用Instant类来表示,Instant也可以用来创建老的java.util.Date对象。

Clock clock = Clock.systemDefaultZone();
long millis = clock.millis();
Instant instant = clock.instant();
Date legacyDate = Date.from(instant

新API中时区使用ZoneId来表示。时区可以很方便的使用静态方法of来获取到。

时区定义了到UTS时间的时间差,在Instant时间点对象到本地日期对象之间转换的时候是极其重要的。

ZoneId zone1 = ZoneId.of("Europe/Berlin");
ZoneId zone2 = ZoneId.of("Brazil/East");
System.out.println(zone1.getRules());
System.out.println(zone2.getRules());
LocalTime定义了一个没有时区信息的时间,例如晚上7点。下面的例子使用前面代码创建的时区创建了两个本地时间。之后比较时间并以小时和分钟为单位计算两个时间的时间差:

LocalTime now1 = LocalTime.now(zone1);
LocalTime now2 = LocalTime.now(zone2);
System.out.println(now1.isBefore(now2));  // false
long hoursBetween = ChronoUnit.HOURS.between(now1, now2);
long minutesBetween = ChronoUnit.MINUTES.between(now1, now2);
LocalDate表示了一个确切的日期,比如 2015-04-10。该对象值是不可变的,用起来和 LocalTime基本一致。下面的例子展示了如何给 Date对象加减天/月/年。另外要注意的是这些对象是不可变的,操作返回的总是一个新实例。

LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS);
LocalDate yesterday = tomorrow.minusDays(2);
LocalDate independenceDay = LocalDate.of(2014, Month.JULY, 4);
DayOfWeek dayOfWeek = independenceDay.getDayOfWeek();
LocalDateTime同时表示了时间和日期,相当于前两节内容合并到一个对象上了。 LocalDateTimeLocalTimeLocalDate都是不可变的。 LocalDateTime提供了一些能访问具体字段的方法。

LocalDateTime time = LocalDateTime.of(2015, Month.April, 10, 4, 10, 1);
DayOfWeek dayOfWeek = time.getDayOfWeek();
附加上时区信息,就可以将其转换为一个时间点 Instant对象, Instant时间点对象可以很容易的转换为老式的 java.util.Date:

在实际项目中,我们一般会通过Date对象来对时间进行存储,但是Date对象并没有开放相关的API对时间进行操作(比如修改当前hour的值)。此时,我们可以通过下列方式来在LocalDateTimeDate之间进行互相转换,将Date转换为LocalDateTime后再对时间进行操作

  • Date 转换为 LocalDateTime
Date date = new Date();
Instant instant = Instant.ofEpochMilli(date.getTime());
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
  • LocalDateTime 转换为 Date
LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date date = Date.from(zdt.toInstant());
十八、第三方库

Java开发中最经常做的一件事情就是管理项目的依赖,所谓的依赖其实就是第三方的库,以JAR包的形式存在。JAR包就是把编译好的类用Zip格式压缩存储在一个文件中。引入JAR包,我们就能够使用JAR包公共的类及其方法和属性。

Java开发中大多数常用的功能其实都有非常优秀的第三方库实现了,给我们提供了很多“轮子”,我们造汽车的时候直接拿来就可以了。

我们现在需要进行文件操作,这里我们准备使用Apache Commons IO提供的一个文件操作库来实现博客信息的加载和存储。

当然我们也可以使用JDK自带的IO功能来实现,不过你需要学习Java IO相关的类和接口。

事实上了解API可能是成为一个编程高手花时间最多的一个地方。当然你也不可能把所有API完全记下来。

在软件开发中也有二八原则,少数的API能够胜任开发中的大部分场景。所以你只需要掌握这些关键部分,当在新场景下遇到不能解决的新问题时,再去查看帮助文档。所以帮助文档的阅读也是技术学习的一个关键因素。了解了基础原理之后一般就能上手开发了,帮助文档可以帮助你在实践中学习。

我们现在需要进行文件操作,这里我们准备使用Apache Commons IO提供的一个文件操作库来实现博客信息的加载和存储。

回到我们的项目,要使用第三方的库,需要将其加入到类路径当中。

  • Apache Commmons IO官方网站下载最新的库,现在的版本是2.4。
  • 解压之后,找到commons-io-2.4.jar,在项目中新建一个文件夹,命名为lib,将该文件拷贝进入lib文件夹。
  • 在Eclipse中右键点击该文件,【Build Path】->【Add to Build Path】就将这个JAR包加入到类路径当中了。只需要在代码中,进行import就能使用其中的类了。

将来我们引入其他JAR包也可以按照相同的方式来进行操作。

让一个类只能创建一个实例的做法,是一种典型的设计模式,成为 Singleton模式。设计模式你可能还是第一次听说,你现在只要知道设计模式是一种常用的定义类的方式就好了,这些方式能更好地适应某些特定的应用场景。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值