Java面向对象系列[v1.0.0][Scanner|DATE|CALENDAR|TIME|logging]

Java程序的参数

public static void main(String[] args){...}


public class ArgsTest
{
    public static void main(String[] args)
    {
        // 输出args数组长度
        System.out.println(args.length);
        // 遍历args数组的每个元素
        for (String arg : args)
        {
            System.out.println(arg);
        }
    }
}
  • Java类由JVM调用,为了让JVM可以自由调用,必须使用public修饰
  • JVM不会创建主类的对象,然后再由对象调用主类的方法,而是通过该类直接调用类方法,因此使用static
  • 主方法被JVM调用,返回值毫无意义,因此使用void
  • main方法的字符串数组形参由调用者JVM负责赋值,在执行命令的时候直接传实参

Scanner

一次性传入固定的参数是一种比较简单的情况,然而往往需要在程序执行的过程中获取输入,可以使用Scanner类,示例代码如下,Scanner类是一个基于正则表达式的文版扫描器,它可以从文件、输入流、字符串中解析出基本类型值和字符串值;Scanner提供了多个构造器,分别用于接收文件、输入流、字符串作为数据源

package demo;
import java.util.*;
import static java.lang.System.*;

/**
 * @author davieyang
 */
public class ScannerKeyBoardTest
{
    public static void main(String[] args)
    {
        // System.in代表标准输入,就是键盘输入
        var sc = new Scanner(in);
        // 增加下面一行将只把回车作为分隔符
        // sc.useDelimiter("\n");
        // 判断是否还有下一个输入项
        while (sc.hasNext())
        {
            // 输出输入项
            out.println("键盘输入的内容是:" + sc.next());
        }
    }
}

执行代码然后敲回车,便可以看到Scanner类的作用

package demo;
import java.util.*;
import static java.lang.System.*;

public class ScannerLongTest 
{
    public static void main(String[] args)
    {
        // System.in代表标准输入,就是键盘输入
        var sc = new Scanner(in);
        // 判断是否还有下一个long型整数
        while (sc.hasNextLong())
        {
            // 输出输入项
            out.println("键盘输入的内容是:" + sc.nextLong());
        }
    }
}
package demo;
import java.util.*;
import java.io.*;
import static java.lang.System.*;

public class ScannerFileTest
{
    public static void main(String[] args) throws Exception
    {
        // 将一个File对象作为Scanner的构造器参数,Scanner读取文件内容
        String filepath =  "src/demo/ScannerFileTest.java";
        Scanner sc = new Scanner(new File(filepath));
        out.println("ScannerFileTest.java文件内容如下:");
        // 判断是否还有下一行
        while (sc.hasNextLine())
        {
            // 输出文件中的下一行
            out.println(sc.nextLine());
        }
    }
}
package demo;
import java.util.*;
import java.io.*;
import static java.lang.System.*;

public class ScannerFileTest
{
    public static void main(String[] args) throws Exception
    {
        // 将一个File对象作为Scanner的构造器参数,Scanner读取文件内容
        Scanner sc;
        sc = new Scanner(new File("ScannerFileTest.java"));
        out.println("ScannerFileTest.java文件内容如下:");
        // 判断是否还有下一行
        while (sc.hasNextLine())
        {
            // 输出文件中的下一行
            out.println(sc.nextLine());
        }
    }
}


package demo;
import java.io.*;
import static java.lang.System.*;

public class KeyboardInTest
{
    public static void main(String[] args) throws Exception
    {
        // 以System.in节点流为基础,创建一个BufferedReader对象
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String line = null;
        // 逐行读取键盘输入
        while ((line = br.readLine()) != null)
        {
            out.println("用户键盘输入是:" + line);
        }
    }
}

日历日期时间日志类

DATE类

Java提供了Date类来处理日期、时间,从JDK1.0开始就有了Date类,现如今大部分构造器和方法已经过时不再使用,Date类提供了6个构造器,其中4个已经会被标记为deprecated,剩下的两个构造器:

  • Date():生成一个代表当前日期时间的Date对象,该构造器在底层调用System.currentTimeMillis()获得long整数坐位日期参数
  • Date(long date):根据指定的long型整数来生成一个Date对象,该构造器的参数表示创建的Date对象和GMT1970年1月1日00:00:00之间的时间差,以毫秒作为计时单位

Date对象的大部分方法也deprecated了,剩下的方法如下:

  • boolean after(Date when):测试该日期是否在指定日期when之后
  • boolean before(Date when):
  • long getTime():返回该时间对应的long型整数,即从 1970-01-01 00:00:00 到该Date对象之间的时间差,以毫秒为单位
  • void setTime(long time):设置该Date对象的时间
package demo;
import java.util.*;
import static java.lang.System.*;

public class DateTest {
    public static void main(String[] args){
        Date date1;
        date1 = new Date();
        Date date2;
        date2 = new Date(currentTimeMillis() + 100);
        out.println(date2);
        out.println(date1.compareTo(date2));
        out.println(date1.before(date2));
    }
}

CALENDAR类

Calendar是一个抽象类,用于表示日历,它是所有日历类的模板,并提供了一些所有日历通用的方法,但本身不能实例化只能被继承后再创建子类的实例,Java本身提供了一个GregorianCalendar类,用于代表公历。
也可以创建自己的子类,然后将它作为Calendar对象使用(这就是多态)
Calendar与Date都是日期类,它们直接可以自由转换:

// 创建一个默认的Calendar对象
Calendar calendar1;
calendar1 = Calendar.getInstance();
// 从Calendar中取出Date对象
Date date3;
date3 = calendar1.getTime();
out.println("date3 is" + date3);
/*
通过Date对象获得对应的Calendar对象,因为Calendar/GregorianCalendar没有构造函数接受Date对象
所以必须先获得一个Calendar实例,然后调用其setTime()方法
*/
Calendar calendar2;
calendar2 = Calendar.getInstance();
calendar2.setTime(date3);
out.println("calendar2 is" + calendar2);

Calendar类提供了大量访问、修改日期时间的方法,常用的如下:

  • void add(int field, int amount):根据日历规则,为给定的日历字段添加或减去指定的时间量
  • int get(int field):返回指定日历字段的值
  • int getActualMaximum(int field):返回指定日历字段可能拥有的最大值,例如月,最大值为11
  • int getActualMinimum(int field):返回指定日历字段可能拥有的最小是,例如月,最小值为0
  • void roll(int field, int amount):与add()方法类似,区别在于加上amount后超过了该字段所能表示的最大范围时,也不会向上一个字段进位
  • void set(int field, int value):将给定的日历字段设置为给定值
  • void set(int year, int month, int date):设置Calendar对象的年月日三个字段值
  • void set(int year, int month, int date, int hourOfDay, int minute, int second):设置Calendar对象的年月日时分秒三个字段值
package demo;
import java.util.*;
import static java.util.Calendar.*;

public class CalendarTest
{
    public static void main(String[] args)
    {
        var c = Calendar.getInstance();
        // 取出年
        System.out.println(c.get(YEAR));
        // 取出月份
        System.out.println(c.get(MONTH));
        // 取出日
        System.out.println(c.get(DATE));
        // 分别设置年、月、日、小时、分钟、秒
        c.set(2003, 10, 23, 12, 32, 23); //2003-11-23 12:32:23
        System.out.println(c.getTime());
        // 将Calendar的年前推1年
        c.add(YEAR, -1); //2002-11-23 12:32:23
        System.out.println(c.getTime());
        // 将Calendar的月前推8个月
        c.roll(MONTH, -8); //2002-03-23 12:32:23
        System.out.println(c.getTime());


        var cal1 = Calendar.getInstance();
        cal1.set(2003, 7, 23, 0, 0, 0); // 2003-8-23
        cal1.add(MONTH, 6); //2003-8-23 => 2004-2-23
        System.out.println(cal1.getTime());


        var cal2 = Calendar.getInstance();
        cal2.set(2003, 7, 31, 0, 0, 0); // 2003-8-31
        // 因为进位到后月份改为2月,2月没有31日,自动变成29日
        cal2.add(MONTH, 6); // 2003-8-31 => 2004-2-29
        System.out.println(cal2.getTime());


        var cal3 = Calendar.getInstance();
        cal3.set(2003, 7, 23, 0, 0, 0); //2003-8-23
        // MONTH字段“进位”,但YEAR字段并不增加
        cal3.roll(MONTH, 6); //2003-8-23 => 2003-2-23
        System.out.println(cal3.getTime());


        var cal4 = Calendar.getInstance();
        cal4.set(2003, 7, 31, 0, 0, 0); //2003-8-31
        // MONTH字段“进位”后变成2,2月没有31日,
        // YEAR字段不会改变,2003年2月只有28天
        cal4.roll(MONTH, 6); //2003-8-31 => 2003-2-28
        System.out.println(cal4.getTime());
    }
}

程序中使用了静态导入,它导入了Calendar类里所有的的类变量,所以可以直接使用Calendar类的YEAR、MONTH、DATE等变量
使用Calendar类需要注意:

add和rolld的区别:

add(int field, int amount),主要用于改变Calendar的特定字段的值,如果需要增加某字段的值则让amount为正数,如果需要减少某字段的值,则让amount为负数即可,当被修改的字段超过它允许的范围时,会发生进位

Calendar cal1 = Calendar.getInstance();
cal1.set(2003, 7, 23, 0, 0, 0);//2003-08-23
cal1.add(MONTH, 6);// 2003-8-23 => 2004-2-23

如果下一级字段也需要改变,那么该字段会修正到变化最小的值

Calendar cal2 = Calendar.getInstance();
cal2.set(2003, 7, 31, 0, 0, 0);//2003-8-31, 进位后变为2月,2月没有31日,自动变为29日
cal2.add(MONTH, 6);//2003-8-31 => 2004-2-29

roll()的规则则少有不同,当被修改的字段超过范围,不进行进位

Calendar cal3 = Calendar.getInstance();
cal3.set(2003, 7, 23, 0, 0, 0);
cal3.roll(MONTH, 6);
Calendar cla4 = Calendar.getInstance();
cal4.set(2003, 7, 31, 0, 0, 0);
cal4.roll(MONTH, 6);

当使用set方法的时候,可能传入不合法的参数,例如MONTH设置为13

package demo;
import java.util.*;
import static java.util.Calendar.*;
import static java.lang.System.*;

public class LenientTest
{
    public static void main(String[] args)
    {
        var cal = Calendar.getInstance();
        // 结果是YEAR字段加1,MONTH字段为1(二月)
        cal.set(MONTH, 13);   
        out.println(cal.getTime());
        // 关闭容错性
        cal.setLenient(false);
        // 导致运行时异常
        cal.set(MONTH, 13);   
        out.println(cal.getTime());
    }
}

set(f, value)方法将日历字段f更改为value,尽管日历字段的f是立即被更改的,但该Calendar所代表的时间却不会立即修改,直到下次调用get(),getTime(),getTimeInMillis(),add(),roll()时,才会重新计算日历时间,这被称为set()方法的延迟修改

package demo;
import java.util.*;
import static java.util.Calendar.*;
import static java.lang.System.*;

public class LazyTest
{
    public static void main(String[] args)
    {
        var cal = Calendar.getInstance();
        // 2003-8-31
        cal.set(2003, 7, 31);
        // 将月份设为9,但9月31日不存在。
        // 如果立即修改,系统将会把cal自动调整到10月1日。
        cal.set(MONTH, 8);
        // 下面代码输出10月1日
        // System.out.println(cal.getTime());
        // 设置DATE字段为5
        cal.set(DATE, 5);
        out.println(cal.getTime());
    }
}

JAVA8新增TIME类

  • Clock:该类用于获取指定时区的当前日期、时间,该类可取代System类的currentTimeMillis()方法,而且提供了更多方法来获取当前日期、时间,该类还提供了大量的静态方法来获取Clock对象
  • Duration:该类代表持续时间,用于获取一段时间
  • Instant:代表一个具体时间,精确到纳秒,它提供了几个实用的静态方法now(),now(Clock, clock)用于获取当前时刻minusXxx(),plusXxx()方法在当前时刻减去或增加一段时间
  • LocalDate:该类代表不带时区的日期,它也提供了now(),now(Clock, clock),minusXxx(),plusXxx()静态方法
  • LocalTime:该类代表不带时区的时间,其他的同LocalDate
  • LocalDateTime:该类代表不带时区的日期,时间,其他的同LocalDate
  • MonthDay:该类仅代表月日,它也提供了now()和now(Clock clock)静态方法
  • Year:今代表年,它也提供了now(),now(Clock clock),minuxXxx(),plusXxx()静态方法
  • YearMonth:代表年月,它也提供了now(),now(Clock clock),minuxXxx(),plusXxx()静态方法
  • ZonedDateTime:代表一个时区化的日期、时间
  • ZoneId:代表一个时区
  • DayOfWeek:枚举类,定义了周日到周六的枚举值
  • Month:枚举类,定义了一月到十二月的枚举值
package demo;
import java.time.*;
import static java.lang.System.*;

public class NewDatePackageTest
{
    public static void main(String[] args)
    {
        // -----下面是关于Clock的用法-----
        // 获取当前Clock
        var clock = Clock.systemUTC();
        // 通过Clock获取当前时刻
        out.println("当前时刻为:" + clock.instant());
        // 获取clock对应的毫秒数,与System.currentTimeMillis()输出相同
        out.println(clock.millis());
        out.println(System.currentTimeMillis());
        // -----下面是关于Duration的用法-----
        var d = Duration.ofSeconds(6000);
        out.println("6000秒相当于" + d.toMinutes() + "分");
        out.println("6000秒相当于" + d.toHours() + "小时");
        out.println("6000秒相当于" + d.toDays() + "天");
        // 在clock基础上增加6000秒,返回新的Clock
        var clock2 = Clock.offset(clock, d);
        // 可以看到clock2与clock1相差1小时40分
        out.println("当前时刻加6000秒为:" +clock2.instant());
        // -----下面是关于Instant的用法-----
        // 获取当前时间
        var instant = Instant.now();
        out.println(instant);
        // instant添加6000秒(即100分钟),返回新的Instant
        var instant2 = instant.plusSeconds(6000);
        out.println(instant2);
        // 根据字符串解析Instant对象
        var instant3 = Instant.parse("2014-02-23T10:12:35.342Z");
        out.println(instant3);
        // 在instant3的基础上添加5小时4分钟
        var instant4 = instant3.plus(Duration
                .ofHours(5).plusMinutes(4));
        out.println(instant4);
        // 获取instant4的5天以前的时刻
        var instant5 = instant4.minus(Duration.ofDays(5));
        out.println(instant5);
        // -----下面是关于LocalDate的用法-----
        var localDate = LocalDate.now();
        out.println(localDate);
        // 获得2014年的第146天
        localDate = LocalDate.ofYearDay(2014, 146);
        out.println(localDate); // 2014-05-26
        // 设置为2014年5月21日
        localDate = LocalDate.of(2014, Month.MAY, 21);
        out.println(localDate); // 2014-05-21
        // -----下面是关于LocalTime的用法-----
        // 获取当前时间
        var localTime = LocalTime.now();
        // 设置为22点33分
        localTime = LocalTime.of(22, 33);
        out.println(localTime); // 22:33
        // 返回一天中的第5503秒
        localTime = LocalTime.ofSecondOfDay(5503);
        out.println(localTime); // 01:31:43
        // -----下面是关于localDateTime的用法-----
        // 获取当前日期、时间
        var localDateTime = LocalDateTime.now();
        // 当前日期、时间加上25小时3分钟
        var future = localDateTime.plusHours(25).plusMinutes(3);
        out.println("当前日期、时间的25小时3分之后:" + future);
        // -----下面是关于Year、YearMonth、MonthDay的用法示例-----
        var year = Year.now(); // 获取当前的年份
        out.println("当前年份:" + year); // 输出当前年份
        year = year.plusYears(5); // 当前年份再加5年
        out.println("当前年份再过5年:" + year);
        // 根据指定月份获取YearMonth
        var ym = year.atMonth(10);
        out.println("year年10月:" + ym); // 输出XXXX-10,XXXX代表当前年份
        // 当前年月再加5年、减3个月
        ym = ym.plusYears(5).minusMonths(3);
        out.println("year年10月再加5年、减3个月:" + ym);
        var md = MonthDay.now();
        out.println("当前月日:" + md); // 输出--XX-XX,代表几月几日
        // 设置为5月23日
        var md2 = md.with(Month.MAY).withDayOfMonth(23);
        out.println("5月23日为:" + md2); // 输出--05-23
    }
}

日志类

在Java9之后强化了日志API,开发者可将这些日志消息路由到各种主流的日志框架,例如SLF4J、Log4J等等,否则将默认使用Java传统的java.util.logging日志API
日志API用起来非常简单,只需要两个步骤

  • 调用System类的getLogger(String name)方法获取System.Logger对象
  • 调用System.Logger对象的log()方法输出日志,该方法的第一个参数用于指定日志级别
    Java面向对象系列[v1.0.0][Scanner|DATE|CALENDAR|TIME|logging]_第1张图片
import java.util.logging.*;

public class LoggerTest
{
    public static void main(String[] args) throws Exception
    {
        // 获取System.Logger对象
        var logger = System.getLogger("fkjava");
        // 设置系统日志级别(FINE对应DEBUG)
        Logger.getLogger("fkjava").setLevel(Level.FINE);
        // 设置使用a.xml保存日志记录
        Logger.getLogger("fkjava").addHandler(new FileHandler("a.xml"));
        logger.log(System.Logger.Level.DEBUG, "debug信息");
        logger.log(System.Logger.Level.INFO, "info信息");
        logger.log(System.Logger.Level.ERROR, "error信息");
    }
}


<log>
<record>
  <date>2020-03-21T05:24:13.302062800Zdate>
  <millis>1584768253302millis>
  <nanos>62800nanos>
  <sequence>0sequence>
  <logger>logger_demologger>
  <level>FINElevel>
  <class>demo.LoggerTestclass>
  <method>mainmethod>
  <thread>1thread>
  <message>debug信息message>
record>
<record>
  <date>2020-03-21T05:24:13.336085Zdate>
  <millis>1584768253336millis>
  <nanos>85000nanos>
  <sequence>1sequence>
  <logger>logger_demologger>
  <level>INFOlevel>
  <class>demo.LoggerTestclass>
  <method>mainmethod>
  <thread>1thread>
  <message>info信息message>
record>
<record>
  <date>2020-03-21T05:24:13.460166Zdate>
  <millis>1584768253460millis>
  <nanos>166000nanos>
  <sequence>2sequence>
  <logger>logger_demologger>
  <level>SEVERElevel>
  <class>demo.LoggerTestclass>
  <method>mainmethod>
  <thread>1thread>
  <message>error信息message>
record>
log>

在这里插入图片描述

国际化日志输出

package demo;

import java.util.logging.*;
import java.util.*;


public class LoggerI18N
{
    public static void main(String[] args) throws Exception
    {
        // 加载国际化资源包
        var rb = ResourceBundle.getBundle("logMess", Locale.getDefault(Locale.Category.FORMAT));
        // 获取System.Logger对象
        var logger = System.getLogger("logger_demo", rb);
        // 设置系统日志级别
        Logger.getLogger("logger_demo").setLevel(Level.INFO);
        // 设置使用a.xml保存日志记录
        Logger.getLogger("logger_demo").addHandler(new FileHandler("logger_demo.xml"));
        // 下面3个方法的第二个参数是国际化消息的key
        logger.log(System.Logger.Level.DEBUG, "debug");
        logger.log(System.Logger.Level.INFO, "info");
        logger.log(System.Logger.Level.ERROR, "error");
    }
}

在src目录下新建两个属性文件logMess_en_US.properties和logMess_zh_CN.properties,分别写入如下内容
debug=Debug Messageinfo=Plain Messageerror=Error Message
debug=调试信息info=普通信息error=错误信息
在这里插入图片描述



<log>
<record>
  <date>2020-03-21T07:02:00.374406100Zdate>
  <millis>1584774120374millis>
  <nanos>406100nanos>
  <sequence>0sequence>
  <logger>logger_demologger>
  <level>INFOlevel>
  <class>demo.LoggerI18Nclass>
  <method>mainmethod>
  <thread>1thread>
  <message>普通信息message>
  <key>infokey>
  <catalog>logMesscatalog>
record>
<record>
  <date>2020-03-21T07:02:00.487481300Zdate>
  <millis>1584774120487millis>
  <nanos>481300nanos>
  <sequence>1sequence>
  <logger>logger_demologger>
  <level>SEVERElevel>
  <class>demo.LoggerI18Nclass>
  <method>mainmethod>
  <thread>1thread>
  <message>错误信息message>
  <key>errorkey>
  <catalog>logMesscatalog>
record>
log>

你可能感兴趣的:(Java基础即高端)