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);
}
}
}
一次性传入固定的参数是一种比较简单的情况,然而往往需要在程序执行的过程中获取输入,可以使用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);
}
}
}
Java提供了Date类来处理日期、时间,从JDK1.0开始就有了Date类,现如今大部分构造器和方法已经过时不再使用,Date类提供了6个构造器,其中4个已经会被标记为deprecated,剩下的两个构造器:
Date对象的大部分方法也deprecated了,剩下的方法如下:
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是一个抽象类,用于表示日历,它是所有日历类的模板,并提供了一些所有日历通用的方法,但本身不能实例化只能被继承后再创建子类的实例,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类提供了大量访问、修改日期时间的方法,常用的如下:
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(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());
}
}
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用起来非常简单,只需要两个步骤
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>