Java从入门到烧烤
JDK的安装
JDK和JRE
- 什么是JRE?
JRE(Java Runtime Environment)是java程序的运行环境,最核心的内容就是JVM(Java虚拟机)和核心类库。 - 什么是JDK?
JDK(Java Development Kit)是java的开发环境,包含了JRE,并提供了额外的开发者工具,例如javac
、javaw
等。
JDK的下载
推荐使用BellSoft的Liberica JDK。未来开发中可以根据需要选择不同的JDK版本。
配置JDK环境
- 打开设置-系统-系统信息-高级系统设置-环境变量。
- 在系统变量下新建变量名
JAVA_HOME
,变量值选择JDK目录。 - 打开系统变量下的
Path
变量,新建一个值,名为%JAVA_HOME%\bin
,并建议将其置于前列。这样在我们有不同需要时,更改JAVA_HOME
下的路径,即可切换不同的JDK版本。
- 配置完成后,打开
cmd
输入java -version
查看版本,能够查看到结果就说明已经成功安装并配置了JDK。
Java程序入门
第一个Java程序
1 | public class HelloJava { |
我们将上述代码拆解:
- java中的类,将在后续介绍。
1
2
3public class HelloJava{
} - java程序的入口点,称之为主方法。主方法中编写的代码将从上到下依次执行。
1
2
3public static void main(String[] args) {
} - java语法的代码。该代码和C语言中的
printf()
功能几乎相同。在java中,每一条完整的语句都需要以;
结尾。1
2System.out.println("Hello, Java!");
System.out.println("Hello World!");
注释
java中的注释分为三种:
- 单行注释。 通过
1
// 单行注释。
//
表示注释掉后面的内容,仅注释单行。 - 多行注释。 通过
1
2
3
4/*
这是多行注释。
可以表示多行文本内容。
*//* */
表示,其中间的每一行都会被注释。 - 文档注释。 文档注释在多行注释的基础上,允许在程序中嵌入关于程序的信息,可以使用额外的参数生成文档,例如上述的
1
2
3
4
5
6/**
* 这是文档注释。
* main方法是程序的入口。
* @author Soria
* @param args 命令行参数
*/@author
和@param
。具体查看【[[#文档注释]]】。
变量和常量
常量
常量使用final
修饰,具体为final 数据类型 标识符
。常量只有第一次赋值时可以更改它的值,后续将不能修改。
1 | final int a = 10; |
变量
变量的值可以修改,具体为数据类型 标识符
。
1 | int a = 20; |
标识符的命名要求
- 标识符可以由大小写字母、数字、下划线
_
和美元符号$
组成,但是不能以数字开头。 - 变量不能重复定义,大小写敏感,A和a就是两个不同的变量。
- 不能有
@
、#
、+
、-
、/
等符号。 - 应该使用有意义的名称,一般我们采用英文单词,以小写字母开头。
- 不可以是
true
和false
。 - 不能与java语言的关键字或是基本数据类型重名。
基本数据类型
整数类型
java中的整数类型包含下面几种:
类型 | 取值范围 |
---|---|
byte |
-128~127 |
short |
-32768~32767 |
int |
-231~231-1 |
long |
-263~263-1 |
上述变量都可以表示整数,且由于大小关系,可以将小整数类型传递给大整数类型。 |
1 | short a = 120; |
手动赋值时的数值默认是int
类型,在表达long
类型的变量时,需要在结尾添加大写或小写的L
。如果数值过大,我们可以用_
分隔,便于提升可阅读性。
1 | long a = 922337203685477580L; |
在java中还可以通过不同的进制来表示常量或变量值。
1 | int a = 0b10101010; // 二进制 |
浮点类型
浮点类型包含单精度浮点型float
和双精度浮点型double
。
浮点类型的取值范围如下:
float
:1.4*10-45~3.4028235*1038double
:4.9*10-324~1.7976931348623157*10308
创建浮点类型时,默认为double
类型,在表达float
类型的变量时,需要在结尾添加大写或小写的F
。1
2float f = 9.9F;
double d = 12.55;
字符类型
java中的字符类型为char
,其存储的内容依旧是数字,范围为0~65535,每个数字都对对应着一个字符,具体需查看ASCII码表。
我们既可以用ASCII码表所对应的数字表示字符,也可以直接将字符常量赋值。两种写法的效果没有区别。
1 | char c1 = 65; |
char
实际上需要两个字节才能表示更多种类的字符,因此可以表示中文字符。使用int
类型接收字符类型常量值可以直接转换为对应的编码。
1 | int a = '你'; |
如果遇到多个字符,我们需要使用String
类型表示。String
类型并不是基本数据类型,而是对象类型,将在之后介绍。
1 | String str = "你好,世界"; |
布尔类型
布尔类型常用于存放状态,只有true
和false
两种值,表示真和假,常用于流程控制语句。
1 | boolean a = true; |
隐式转换
1 | long l = 21731371236768L; |
隐式转换是指在不需要显式声明的情况下,自动将一种较小的类型转换为较大的兼容类型。当在表达式中混合使用不同类型的变量时,会自动将较小类型提升为较大类型进行运算。
1 | int a = 10; |
当涉及到 byte
、short
或char
类型的运算时,这些类型会自动提升为int
,即使两者的值都很小。这是为了确保计算的准确性和避免可能的溢出问题。
1 | byte b = 10; |
隐式类型转换规则:byte
→short(char)
→int
→long
→float
→double
。
显式转换
当需要将较大的数据类型转换为较小的数据类型时,必须手动完成。
1 | double d = 9.99; |
数据丢失是显示转换的常见问题。
运算符
赋值运算符
赋值运算符:=
。 其左边必须是一个可以赋值的目标,比如变量,右边可以是任意满足要求的值,包括变量。
当出现连续使用赋值运算符时,按照从右往左的顺序进行计算,b
被赋值为666
。赋值运算的计算结果就是赋的值本身,此时继续进行赋值计算,c
将被赋值为b = 666
的计算结果,所以c
的值也为666
。
1 | int a = 666; // 对变量a进行赋值 |
算数运算符
算数运算符:+
(加法)、-
(减法)、*
(乘法)、/
(除法)、%
(取余)。这些运算符均具有参与基本数据类型计算的能力。值得注意的是,两个整数在进行/
运算时,得到的结果会舍去小数部分,保留整数。
1 | int a = 10; |
+
还支持字符串与字符串的拼接,以及和基本数据类型的拼接。
1 | String str1 = "测试内容:" + "拼接字符串"; |
括号运算符
和数学运算符的括号相同,可以使用()
提升内部运算的优先级。
1 | int a = 10; |
括号也可以嵌套,但不像数学中使用[]
和{}
,统一使用()
。
1 | int a = (1+(2 - 3) * 4) * 5; |
()
还用作显式转换。
1 | int a = 10; |
通过显式转换,可以将两个整数相除得到的结果变为小数。
1 | int a = 10, b = 3; |
自增自减运算符
自增自减运算符一般和变量进行使用。
1 | int a = 5; |
自增自减运算符还可以位于变量前面,例如++a
,--b
,效果和上述相同。但是两种方式的计算顺序不一样。
1 | int a = 10; |
当自增自减运算符在变量后面时,先计算结果在自增自减。反之在前面时,则相反。
自增自减运算符还可以用于其他数的自增自减,而不是1。
1 | int a = 10; |
算数运算符+
、-
、*
、/
都能和自增自减运算符相组合。
位运算符
位运算符比较偏向底层,包括四种运算符:&
、|
、^
、~
。
&
:按位与,两个数的每一位相比较,相同则为1,不同则为0;|
:按位或,两个数的每一位相比较,其中一个为1则为1,两个都为0则为0;^
:按位异或,两个数的每一位相比较,不同则为1,相同则为0;~
:按位取反,对一个数的每一位取反,原来为1则为0,原来为0则为1;除了上述四个位运算符,还有位移运算符:1
2
3
4
5int a = 3, b = 6; // a = 0011, b = 0110;
System.out.println(a & b); // 输出:2 -> 0010
System.out.println(a | b); // 输出:7 -> 0111
System.out.println(a ^ b); // 输出:5 -> 0101
System.out.println(~a); // 输出:-4 -> 1100>>
和<<
。
左移运算符>>
每移动一位,结果会*2
,高位丢弃,低位补0。右移运算符<<
每移动一位,结果都会/2
,低位丢弃,高位补符号位。1
2
3
4
5int a = 3, b = 6;
System.out.println(a << 1); // 输出:6
System.out.println(b >> 1); // 输出:3
// 位移运算符还可以和 = 一起使用
b <<= 1;
关系运算符
关系运算符包括:>
、<
、>=
、<=
、!=
、==
。常用于判断,输出的结果为boolean
类型的true
或false
。
1 | System.out.println(3 > 5); // 输出:false |
逻辑运算符
逻辑运算符有三种:&&
、||
、!
。
&&
:两边同时为true
,则返回true
,否则返回false
。||
:两边有一个为ture
,则返回true
,否则返回false
。!
:对运算结果取反,结果为true
则返回false
,结果为false
则返回true
。1
2
3
4
5
6System.out.println(3 > 2 && 3 > 3); // 输出:false
System.out.println(3 > 1 && 3 > 2); // 输出:true
System.out.println(3 < 4 || 3 < 3); // 输出:true
System.out.println(3 > 3 || 3 < 3) // 输出:false
Sytem.out.println(!(3 > 3)); // 输出:true
System.out.println(!(3 > 2)) // 输出:false
三元运算符
三元运算符的形式为判断语句?结果1:结果2
。如果判断语句结果为true
,返回结果1
,反之则返回结果2
。
1 | int a = 10; |
流程控制语句
代码块和作用域
1 | public static void main(String[] args) { |
变量的使用范围,仅限于其定义时所处的代码块,一旦超出对应的代码块区域,那么就相当于没有这个变量。
选择结构
if
语句
if
语句表示为:if( 判断条件 ) 判断成功执行的代码块;
。
1 | if( 15 > 10) { |
我们还可以通过else
、else-if
来执行其他情况的代码块。
1 | if(15 > 10) { |
switch
语句
switch
语句可以精准的匹配某个值,但不能判断范围。
1 | int a = 10; |
循环结构
while
循环
while
循环的语法为:while (循环条件) 循环体
。
1 | int i = 100; |
当我们不确定何时结束循环时,适合使用while
循环。
我们也可以先执行一次循环体,再做循环判断,需要用到do...while
语句。
1 | int i = 0; |
此时,无论满不满足循环条件,都会先执行一次do
代码块内的内容。
for
循环
for
循环的语法为:for (表达式1; 表达式2; 表达式3) 循环体
。
- 表达式1:循环开始前仅执行一次。
- 表达式2:判断语句,用于判断是否可以结束循环。
- 表达式3:每次循环结束后都会执行一次。
1
2
3
4// 下面的循环会执行3次,每次都会输出一次i的值
for (int i = 0; i < 3; i++) {
System.out.println(i);
}for
循环的三个表达式都不是必需项,可以省略不写。其中,表达式2省略不写会造成无限循环。我们还可以使用1
2
3
4
5int i = 0;
for ( ; i < 3; ) {
System.out.println(i);
i++;
}continue
和break
来提前结束循环。 continue
:跳过本轮循环,直接开始下一轮循环。break
:终止循环,跳出到循环外部。1
2
3
4
5
6
7
8
9
10for (int i = 0; i < 3; i++) {
if (i == 1) continue; // 当i=1时,跳过后续代码,并执行下一轮循环
System.out.println(i);
}
for (int i = 0; i < 3; i++) {
if (i == 0) break; // 当i=1时直接结束循环,并跳出循环,执行输出Hello
System.out.println(i);
}
System.out.println("Hello");
Java程序基础
类与对象
每个.java源文件只能有一个public class
。
1 | public class Person { |
通过new
关键字可以创建一个对象。
1 | Person p = new Person(); |
方法
方法的创建与使用
方法的定义:返回值类型 方法名(参数) { 方法体 }
。
1 | public class Person { |
返回值类型是指方法执行完成后所返回的数据类型,可以是基本类型也可以是引用类型。如果方法没有返回值,可以用void
表示。
1 | Person p = new Person(); |
在需要调用方法时,使用.
运算符即可。
1 | Person p = new Person(); |
方法定义时还可以使用参数。下面我们定义一个加法:
1 | int sum(int a, int b) { |
使用return
关键字后,方法会直接结束并返回结果,后续代码无法到达。
方法的参数传递
方法定义时创建的参数称为形式参数,简称形参。调用方法实际传入的参数称为实际参数,简称实参。
在方法的参数传递时,会在调用方法的时候,对参数的值进行复制,而不是使用传入参数本身。
1 | int a =3, b = 6; |
上述方法中,交换的仅仅是swap
方法里的a
和b
,并不能直接操作外面的数。
当我们操作对象时,情况会有所不同。
1 | void changeName(Person p, String name) { |
此处引用类型p
是对象的引用,而不是对象本身。这里进行的值传递相当于将对象的引用复制到方法内部的变量中,而这个内部的变量引用的依旧是同一个对象。所以此处相当于直接操作外面所定义的对象。
this
关键字的使用
如果我们想要在方法中访问当前对象的属性,可以使用this
关键字。
1 | void getName() { |
方法的重载
我们现在有一个加法:
1 | int sum(int a, int b) { |
该方法只接受int类型的变量。如果我们传入小数,将会出现错误。此时,为了让上述方法支持小数的相加,我们需要对其进行重载。
1 | int sum(int a, int b) { |
方法的重载意味着方法可以重名,但是传入的参数类型不同,又或者是参数的数量不同。返回值既可以相同也可以不同。
如果仅仅是返回值不同,是不支持重载的。
方法的递归调用
方法可以调用其他方法或者自身。方法如果自己调用自己,称之为递归调用。
1 | void sayHello() { |
构造方法
构造方法不需要填写返回值,并且方法名称与类名相同,默认情况下每个类都会自带一个没有任何参数的无参构造方法(只是不用我们去写,编译出来就自带)当然,我们也可以手动声明,对其进行修改。
1 | public class Person{ |
构造方法也支持重载,但在实例化时需要使用我们重载的构造方法,又或者是手动重载一个默认无参构造方法。
1 | public Person(String name, int age) { |
静态变量和静态方法
静态的内容,我们可以理解为是属于这个类的,也可以理解为是所有对象共享的内容。我们通过使用static
关键字来声明一个变量或一个方法为静态的,一旦被声明为静态,那么通过这个类创建的所有对象,操作的都是同一个目标,也就是说,对象再多,也只有这一个静态的变量或方法。一个对象改变了静态变量的值,那么其他的对象读取的就是被改变的值。
1 | public class Person() { |
静态方法同样是属于类的,而不是具体的某个对象。
1 | static String info; |
代码块也可以是静态的。
1 | static String info; |
所有被标记为静态的内容,会在类刚加载的时候就分配,而不是在对象创建的时候分配,所以说静态内容一定会在第一个对象初始化之前完成加载。
包和访问控制
包的声明和导入
包用来区分类的位置。随着我们的程序不断变大,可能会创建各种各样的类,他们可能会做不同的事情,那么这些类如果都放在一起的话,有点混乱,我们可以通过包的形式将这些类进行分类存放。
包的命名规则同样是英文和数字的组合。
- 个体项目(individual),指个人发起,但非自己独自完成的项目,可公开或私有项目,copyright主要属于发起者。 包名为
indi.发起者名.项目名.模块名.…
。 - 单人项目(one-man),指个人发起,但非自己独自完成的项目,可公开或私有项目,copyright主要属于发起者。 包名为
onem.发起者名.项目名.模块名.…
。 - 个人项目(personal),指个人发起,独自完成,可分享的项目,copyright主要属于个人。包名为
pers.个人名.项目名.模块名.…
。 - 私有项目(private),指个人发起,独自完成,非公开的私人使用的项目,copyright属于个人。 包名为
priv.个人名.项目名.模块名.…
。 - 团队项目(team),指由团队发起,并由该团队开发的项目,copyright属于该团队所有。包名为
team.团队名.项目名.模块名.…
。 - 公司项目(company),copyright由项目发起的公司所有。包名为
com.公司名.项目名.模块名.…
。
通过package
关键字,我们可以指明当前类所属的包。当我们需要使用其他包里的类时,可以通过import
关键字导入。
在不同包下的两个类,即使类名相同,也是不同的类。1
2
3
4
5
6
7package com.test;
import com.project.entity.Student;
public class Person {
String name;
int age;
}
访问权限控制
我们可以为成员变量、成员方法、静态变量、静态方法甚至是类指定访问权限,不同的访问权限,有着不同程度的访问限制。
public
- 公共,标记为公共的内容,允许在任何地方被访问。private
- 私有,标记为私有的内容无法被除当前类以外的任何位置访问。protected
- 受保护,标记为受保护的内容可以能被类本身和同包中的其他类访问,也可以被子类访问。什么都不写
- 默认,默认情况下,只能被类本身和同包中的其他类访问。
访问权限 | 当前类 | 同一个包下的类 | 不同包下的类 | 不同包下的子类 |
---|---|---|---|---|
public |
✅ | ✅ | ✅ | ✅ |
private |
✅ | ❌ | ❌ | ❌ |
protected |
✅ | ✅ | ❌ | ✅ |
默认 |
✅ | ✅ | ❌ | ❌ |
封装、继承和多态
封装、继承和多态是面向对象编程的三大特性。
- 封装,把对象的属性和方法结合成一个独立的整体,隐藏实现细节,并提供对外访问的接口。
- 继承,从已知的一个类中派生出一个新的类,叫子类。子类实现了父类所有非私有化的属性和方法,并根据实际需求扩展出新的行为。
- 多态,多个不同的对象对同一消息作出响应,同一消息根据不同的对象而采用各种不同的方法。
类的封装
封装的目的是为了保证变量的安全性,使用者不必在意具体实现细节,而只是通过外部接口即可访问类的成员,如果不进行封装,类中的实例变量可以直接查看和修改,可能给整个代码带来不好的影响,因此在编写类时一般将成员变量私有化,外部类需要使用getter
和setter
方法来查看和设置变量。
1 | public class Person { |
我们还可以将构造方法变为private
,通过我们自己定义的方法来构造对象。
1 | public class Person { |
类的继承
使用extends
关键字,可以让一个类继承另一个类。父类中所定义的方法和属性都会被子类继承,子类可以直接使用父类中的属性和方法。
1 | public class Person { |
类的继承可以不断向下,但是同时只能继承一个类。对于父类中被private
修饰的属性,子类依旧继承了这个属性,但是无法访问。被final
修饰的类不允许被继承。
我们还可以使用强制类型转换,将子类当作其父类使用,也可以将一个被当作父类使用的子类对象转换回子类。
1 | Person p = new Student("小明", 18); // 向上转型 |
instanceof
可以判断某个变量所引用的对象是什么类。
1 | Person p = new Student("小明", 18); |
子类可以拥有和父类同名的变量或方法,通过super
关键字可以使用父类中同名的属性和变量。
1 | public class Person { |
方法的重写
使用@override
注解,我们可以对方法进行重写。
1 | public class Person { |
在重写了Object
类提供的equals
方法后,就会按照我们重写后的方法进行判断,即使是两个不同的对象。注意,被final
和private
修饰的类无法重写。Object
类是所有类的父类,所有类都继承自Object
类。
抽象类
抽象类不是具体的类定义,不可以被new
关键字实例化对象。抽象类相当于定义,具体的实现需要通过子类去完成。
1 | public abstract class Person { |
抽象类一般只用作继承,抽象类的子类也可以是一个抽象类。
接口
接口用于将类所具有的行为抽象出来。接口不同于继承,接口可以同时实现多个。接口中不允许存在成员变量和成员方法,但是可以存在静态变量和静态方法。
1 | public interface Study { |
枚举类
使用enum
定义枚举类:
1 | public enum Status { |
Java程序高级
包装类
基本类型包装类
能够表示数字的基本类型包装类,继承自Number类,对应关系如下表:
基本类型 | 包装类 |
---|---|
byte |
Byte |
boolean |
Boolean |
short |
Short |
char |
Character |
int |
Integer |
long |
Long |
float |
Float |
double |
Double |
包装类型具有自动装箱和拆箱机制,可以更好地参与到基本运算中。 |
1 | Integer a = 10, b = 20; // 自动装箱为包装类 |
特殊包装类
特殊包装类分为用于进行超大数计算的BigInteger
和小数精确计算的BigDecimal
。
1 | public class HelloJava { |
数组
数组用于存放一组相同类型的数据,每一个数据称之为数组的元素。数组的下标从0开始,要访问数组内的元素可以通过下标访问。
1 | // 创建数组并赋值的两种方式 |
创建出来的数组每个位置上都有默认值,如果是引用类型,就是null,如果是基本数据类型,就是0,或者是false,跟对象成员变量的默认值是一样的。
数组的长度length
在创建后就被确定,且被final
修饰。因此数组一旦创建,长度便不可被修改,要使用更大或更小的数组,只能重新创建。
1 | int[] array = new int[10]; |
多维数组
数组中也可以存放数组类型的数据,例如二维数组:
1 | // 数组创建时长度必须被确定。但内层相当于外层数组的一个元素,因此可以不需要确定长度 |
在遍历多维数组时,我们需要嵌套循环。
1 | int[][] array = new int[2][3] {{1, 2, 3}, {4, 5, 6}}; |
可变长参数
方法支持可变长参数,即接收任意数量参数的方法。可变长参数的的本质就是一个数组。
1 | public void test(String... strings){ |
如果同时存在多个参数,那么可变长参数只能放在最后。
1 | public void test(int a, int b, int... arrays) { |
String
String
类
String
本身也是一个类,只不过它比较特殊,每个用双引号括起来的字符串,都是String类型的一个实例对象。
1 | String str = "Hello World"; |
如果是直接使用双引号创建的字符串,如果它们内容相同,为了优化效率,那么始终都是同一个对象。但是如果我们使用构造方法主动创建两个新的对象,那么就是不同的对象了。
1 | String a = "hello"; |
如果我们仅仅是想要判断两个字符串的内容是否相同,不要使用==
,String
类重载了equals
方法用于判断和比较内容是否相同。
1 | System.out.println(c.equals(d)); // 输出:true |
正则表达式
正则表达式用于解决字符串格式匹配问题。具体查看【[[#正则表达式匹配词]]】。
1 | String str = "abcabccaa"; |
内部类
成员内部类
我们可以在类的内部在定义一个类。
1 | public class Outer { |
如果将内部类的访问权限改为private
,那么外部则无法访问到内部类。成员内部类和成员方法、成员变量一样,是对象所有的,而不是类所有的。
1 | Outer out = new Outer(); |
成员内部类可以访问到外部类,也可以通过this
和super
来使用同名变量,我们一般不实例化成员内部类,只会在类的内部自己使用。
静态内部类
静态内部类就像静态方法和静态变量一样,是属于类的,我们可以直接创建使用。
1 | public class Outer { |
静态内部类相当于外部而言,整个内部类处于静态上下文,因此无法访问外部类的非静态属性。
局部内部类
局部内部类使用频率很低,基本用不到。
局部内部类就像局部变量一样,可以在方法中定义。
1 | public class Outer { |
匿名内部类
匿名内部类一般用于抽象类和接口。一般情况下抽象类和接口需要继承或实现,然后再重写内部的方法。我们可以在方法中使用匿名内部类,将其中的抽象方法实现,并直接创建实例对象。
1 | public abstract class Person { |
异常
异常的类型
所有的异常都继承自Exception
类。 异常主要分为运行时异常和编译时异常两大类。运行时异常默认继承自RuntimeException
类,所有的编译时异常默认继承自Exception
类。
自定义异常
要创建自定义异常,只需要继承Exception
类或者RuntimeException
类。
1 | // 编译时异常 |
抛出异常
由于一些原因导致程序执行错误时,例如传入错误的参数,我们可以使用throw
关键字手动抛出一个异常,并在异常的构造方法中写入一个信息来表示造成异常的原因。
1 | public double divide(int a, int b) { |
当出现异常时,程序会终止并报错,并显示出现异常的位置。
如果我们在方法中抛出了一个非运行时异常,那么必须告知函数的调用方我们会抛出某个异常,函数调用方必须要对抛出的这个异常进行对应的处理。运行时异常也可以这样写,但不做强制要求。
1 | //告知调用方此方法会抛出哪些异常,请调用方处理好 |
异常的处理
我们一般使用try...catch
捕获并处理异常。将代码写在try
语句块中,catch
可以捕获到try
中发生的特定异常并进行处理。
1 | try { |
当要捕获的异常是某个异常的子类时,我们对其父类进行捕获同样可以包括到子类。例如:可以直接捕获Exception
类来对所有异常进行捕获,因为Exception
类是所有异常的父类。
1 | try { |
如果我们希望无论发生异常都会执行后续的代码,可以使用try...catch...finally
。在finally
语句块中的代码,无论是否捕获到异常都会执行。
1 | try { |
try
必须搭配catch
或finally
使用。省略掉catch
后则不捕获异常,但finally
语句块依旧会执行。
断言
断言一般用于测试,正常程序中不会使用。使用assert
关键字可以设置断言,如果断言后面的内容为false
,则抛出AssertionException
异常。
1 | int a = 10; |
Lambda表达式
扩展内容
文档注释
标签 | 描述 | 示例 |
---|---|---|
@author |
标识一个类的作者 | @author Soria |
@deprecated |
指定一个过期的类或成员 | @deprecated 这是一个过时的方法,不推荐使用。 |
{@docRoot} |
指明当前文档根目录的路径 | {@docRoot} 路径 |
@exception |
标志一个类抛出的异常 | @exception IOException 异常处理 |
{@inheritDoc} |
从直接父类继承的注释 | {@inheritDoc} 从父类继承的注释 |
{@link} |
插入一个到另一个主题的链接 | {@link #main(String[] args)}方法是程序的入口。 |
{@linkplain} |
插入一个到另一个主题的链接,但该链接显示纯文本字体 | 和上述相同。 |
@param |
说明一个方法的参数 | @param a 一个参数 |
@ImplSpec |
实现要求 | @ImplSpec 这是实现要求 |
@ImplNote |
实现说明 | @ImplNote 这是实现说明 |
@return |
说明返回值类型 | @return 返回结果 |
@see |
插入一个类到另一个类的链接 | @see java.lang.String |
@serial |
说明一个序列化属性 | @serial 描述文本 |
@serialData |
说明通过writeObject() 和writeExternal() 方法写的数据 |
@serialData描述文本 |
@serialField |
说明一个ObjectStreamField 组件 |
@serialField name 姓名 |
@since |
自何时开始 | @since release |
@throws |
和@exception 相同 |
同@exception |
{@value} |
显示常量的值,该常量必须是static |
{@value #a} 是一个常量 |
@version |
指定类的版本 | @version 0.0.1 |
正则表达式匹配词
字符 | 描述 |
---|---|
\ |
将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,“n ”匹配字符“n ”。“\n ”匹配一个换行符。串行“\\ ”匹配“\ ”而“\( ”则匹配“( ”。 |
^ |
匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。 |
$ |
匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。 |
* |
匹配前面的子表达式零次或多次。例如,zo能匹配“z”以及“zoo”。等价于{0,}。 |
+ |
匹配前面的子表达式一次或多次。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。 |
? |
匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“does”或“does”中的“do”。?等价于{0,1}。 |
{n} |
n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。 |
{n,} |
n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。 |
{n,m} |
m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。 |
? |
当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。 |
. |
匹配除“``n”之外的任何单个字符。要匹配包括“``n”在内的任何字符,请使用像“(.|\n)”的模式。 |
(pattern) |
匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“(”或“)”。 |
(?:pattern) |
匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分是很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。 |
(?=pattern) |
正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) |
正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始 |
(?<=pattern) |
反向肯定预查,与正向肯定预查类拟,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。 |
(?<!pattern) |
反向否定预查,与正向否定预查类拟,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。 |
x|y |
匹配x或y。例如,“z|food”能匹配“z”或“food”。“(z|f)ood”则匹配“zood”或“food”。 |
[xyz] |
字符集合。匹配所包含的任意一个字符。例如,“[abc] ”可以匹配“plain ”中的“a ”。 |
[^xyz] |
负值字符集合。匹配未包含的任意字符。例如,“[^abc] ”可以匹配“plain ”中的“p ”。 |
[a-z] |
字符范围。匹配指定范围内的任意字符。例如,“[a-z] ”可以匹配“a ”到“z ”范围内的任意小写字母字符。 |
[^a-z] |
负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z] ”可以匹配任何不在“a ”到“z ”范围内的任意字符。 |
\b |
匹配一个单词边界,也就是指单词和空格间的位置。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”。 |
\B |
匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。 |
\cx |
匹配由x指明的控制字符。例如,\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“c”字符。 |
\d |
匹配一个数字字符。等价于[0-9]。 |
\D |
匹配一个非数字字符。等价于[^0-9]。 |
\f |
匹配一个换页符。等价于\x0c和\cL。 |
\n |
匹配一个换行符。等价于\x0a和\cJ。 |
\r |
匹配一个回车符。等价于\x0d和\cM。 |
\s |
匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。 |
\S |
匹配任何非空白字符。等价于[^ \f\n\r\t\v]。 |
\t |
匹配一个制表符。等价于\x09和\cI。 |
\v |
匹配一个垂直制表符。等价于\x0b和\cK。 |
\w |
匹配包括下划线的任何单词字符。等价于“[A-Za-z0-9_]”。 |
\W |
匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。 |
\xn |
匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,“\x41”匹配“A”。“\x041”则等价于“\x04&1”。正则表达式中可以使用ASCII编码。. |
\num |
匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“(.)\1”匹配两个连续的相同字符。 |
\n |
标识一个八进制转义值或一个向后引用。如果\n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n为一个八进制转义值。 |
\nm |
标识一个八进制转义值或一个向后引用。如果\nm之前至少有nm个获得子表达式,则nm为向后引用。如果\nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若n和m均为八进制数字(0-7),则\nm将匹配八进制转义值nm。 |
\nml |
如果n为八进制数字(0-3),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。 |
\un |
匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,\u00A9匹配版权符号(©)。 |