1. 注解
注解可以在类、方法、构造器、成员变量、参数等地方进行使用,其作用是让其他程序根据注解的信息来决定怎么执行程序。
1.1 自定义注解
自定义注解的形式如下:
public @interface 注解名{
public 属性类型 属性名() default 默认值;
}
特殊属性名:value。 如果注解中只有一个 value
属性,那么使用注解时, value
名称可以不写。
创建一个 Mytest1
的注解,注解源码如下:
public @interface Mytest1 {
String a();
boolean b() default true;
String[] c();
}
使用注解时,可以在注解里面传值,如下,
@Mytest1(a="练习生", c={"唱", "跳", "rap", "篮球"})
public class Test1 {
public static void main(String[] args) throws Exception {
}
}
1.2 元注解
元注解即修饰注解的注解。
常用的元注解有 @Target
以及 @Retention
。
1.2.1 @Target
该注解声明被修饰的注解只能在哪些位置使用,使用注解时使用形式为 @Target(Element.TYPE)
,其中 TYPE
字段可变,可选值如下:
-
TYPE
:作用于类、接口 -
FIELD
:作用于成员变量 -
METHOD
:作用于成员方法 -
PARAMETER
:作用于方法参数 -
CONSTRUCTOR
:作用于构造器 -
LOCAL_VARIABLE
:作用于局部变量 -
ANNOTATION_TYPE
:作用于注解 -
PACKAGE
:作用于包
该元注解可以作用于多个位置,如 @Target({Element.TYPE, Element.FIELD})
1.2.2 @Retention
该注解声明注解的保留周期,使用形式为 @Retention(RetentionPolicy.RUNTIME)
,其中 RUNTIME
字段可选值如下:
-
SOURCE
:只作用于源码阶段,字节码文件中不存在 -
CALSS
:默认值,保留到字节码文件阶段,运行阶段不存在 -
RUNTIME
:一直保留到运行阶段,开发时常用
1.3 注解的解析
有时候加了一行注解后就能够实现很多的功能,看上去注解十分强大,其实不然,注解只是一个获取值的接口,注解本身并不能进行值的操作与解析功能,如果要对注解进行解析,那么需要在另一个文件中利用反射的方式来对其进行解析。
解析注解时,要注意的是,要解析谁上面的注解,就应该先拿到谁。比如要解析类上面的注解,就应该先获得加载类,获取 Class
对象,再通过 Class
对象解析上面的注解;要解析成员方法上面的注解,就应该先获取该成员方法上面的 Method
对象,再通过 Method
对象解析上面的注解。
Class,Method,Field,Constructor
都实现了 AnnotatedElement
接口,故都有解析注解的能力,解析注解主要使用的方法如下:
AnnotatedElement 提供的解析注解的方法 |
|
---|---|
public Annotaion[] getDeclaredAnnotations() |
获取当前对象上面的注解 |
public T getDeclaredAnnotations(Class<T> annotationClass) |
获取指定的注解对象 |
public boolean isAnnotationPresent(Class<Annotation> annotationClass) |
判断当前对象上是否存在某个注解 |
比如我们可以对上面的 Test1
类的 @Mytest1
注解进行解析,解析如下
public class AnalyzeAnnotation {
public static void main(String[] args) {
Class c = Test1.class;
// 判断是否存在Mytest1注解
if(c.isAnnotationPresent(Mytest1.class)){
// 获取注解对象
Mytest1 mytest1 = (Mytest1)c.getDeclaredAnnotation(Mytest1.class);
System.out.println(mytest1.a());
System.out.println(mytest1.b());
System.out.println(Arrays.toString(mytest1.c()));
}
}
}
2. 文件IO
2.1 非流式文件类
在Java语言的 java.io
包中,由File类提供了描述文件和目录的操作与管理方法。但 File
类不是 InputStream
、OutputStream
或 Reader
、Writer
的子类,因为它不负责数据的输入输出,而专门用来管理磁盘文件与目录。
File
类的初始化如下:
// 根据路径来获取文件对象,这里也可以是一个文件夹
File file = new File("ikun.txt");
其常用的方法如下:
方法 | 说明 |
---|---|
boolean createNewFile |
创建一个新的文件 如果存在这样的文件,就不创建了 |
boolean mkdir |
创建文件夹 如果存在这样的文件夹,就不创建了 注意这个方法只能创建单层目录 如果创建多层目录得一层一层创建 |
boolean mkdirs |
创建文件夹,如果父文件夹不存在,会帮你创建出来 可以创建多层目录 当然也可以创建单层目录 |
boolean delete |
删除文件或者文件夹(文件夹是空文件夹才能删除!如果这个文件夹里面有文件,则不能删除! 要删除一个文件夹,该文件夹内不能包含文件或者文件夹) |
boolean renameTo(File dest) |
把文件重命名为指定的文件路径(如果路径名相同,就会改名.如果路径名不同,就是改名并剪切) |
boolean isDirectory() |
判断是否是目录 |
boolean isFile() |
判断是否是文件 |
boolean exists() |
判断是否存在 |
boolean canRead() |
判断是否可读 |
boolean canWrite() |
判断是否可写 |
boolean isHidden() |
判断是否隐藏 |
boolean isAbsolute() |
判断是否使用的是绝对路径 |
File getAbsolutePath() |
获取绝对路径 |
String getParent() |
返回此抽象路径名父目录的路径名字符串,如果此路径名没有指定父目录,则返回 null. |
File getParentFile() |
返回此抽象路径名父目录的抽象路径名,如果此路径名没有指定父目录,则返回 null. |
long getTotalSpace() |
返回此抽象路径名指定的分区大小。 返回总容量 单位字节 |
long getFreeSpace() |
返回此抽象路径名指定的分区中未分配的字节数。返回剩余容量 单位字节 |
String getName() |
获取名称 |
long length() |
获取长度.也就是文件大小,有多少字节数 |
long lastModified() |
获取最后一次的修改时间,单位为毫秒 |
String[] list() |
获取指定目录下的所有文件或者文件夹的名称,然后放入字符串数组 |
File[] listFiles() |
获取指定目录下的所有文件或者文件夹,然后放入File数组 |
2.2 流式文件类
流序列中的数据既可以是未经加工的原始二进制数据,也可以是经一定编码处理后符合某种格式规定的特定数据。因此Java中的流分为两种:
- 字节流:数据流中最小的数据单元是字节
- 字符流:数据流中最小的数据单元是字符, Java中的字符是
Unicode
编码,一个字符占用两个字节。
注意,以下的输入输出流都是相对内存而言的,即输入流是输入到内存,也就是读文件,输出流是从内存输出,也就是写文件。
2.2.1 字节输入流
字节输入流主要使用的是 FileInputStream
函数。
该函数的构造函数有两个形式,分别为 FileInputStream(String name), FileInputStream(File file)
,示例如下:
//直接通过文件地址初始化
FileInputStream fis = new ileInputStream("D:/test/test1.txt");
//通过File对象初始化
File file = new File("D:/test/test1.txt");
FileInputStream fis = new FileInputStream(file)
该读取的形式有两个主要如下:
read() | 读取一个字节(返回对应字节的ascii码值) |
---|---|
read(byte b[]) | 根据字节缓冲数组的长度,进行读取(返回读取的字节数) |
读取示例如下:
// 方式一
FileInputStream fis = new FileInputStream("ikun.txt");
while (true){
//read() 方法:从输入流对象中,一次读取一个字节(返回的是对应字节的ascii码值,int类型)
int hasRead = fis.read();
//当读取到末尾,返回-1,代表文件读取结束
if(hasRead == -1){
break;
}
System.out.print((char) hasRead);
//打印文件中字符的ascii值
//转化为字符:KH96abcdefghijk
}
//最后一定要关闭资源
fis.close();
// 方式二
FileInputStream fis = new FileInputStream("D:/test/test1.txt");
//带缓冲字节数,根据字节缓冲数组的长度,进行读取
byte[] bytes = new byte[5];
//正确写法
int hasRead = 0;
while((hasRead = fis.read(bytes)) > 0){
//每次读取的内容
System.out.println(new String(bytes,0,hasRead));
}
fis.close();
2.2.2 字节输出流
字节输出流主要使用的是 FileOutputStream
函数。
其构造函数如下:
FileOutputStream(File file, boolean append)
FileOutputStream(String name)
FileOutputStream(String name, boolean append)
与输入流的构造函数类似,不过写入的文件不一定要存在,如果文件不存在,会自动创建一个空的文件;其后的 append
参数表示是否以追加的方式写入文件,默认值为 false
即覆盖,若设为 true
即为追加。
该写入的形式有两个主要如下:
write() | 将b.length个字节从指定字节数组写入此文件输出流中 |
---|---|
write(byte b[], int off, int len) | 将指定字节数组中从偏移量off开始的len个字节写入此文件输出流 |
示例如下:
String string = "Ikun班,正在学习文件输出流,输出文件2";
//JDK1.7以后,只需将资源初始化放在try()里面就可以不用手动关闭流资源,推荐使用;
try(FileOutputStream fos = new FileOutputStream("D:/test/test2.txt",true)){
//将字符串转成字节数组,写入目标文件
fos.write(string.getBytes());
//手动刷新缓冲区
fos.flush();
}catch (IOException e){
e.printStackTrace();
}
2.2.3 字符输入流
Java中字符是采用Unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,JAVA中引入了处理字符的流。
其构造函数如下:
FileReader(File file)
FileReader(String fileName)
读取如下:
read() | 按单个字符读取 |
---|---|
read(char cbuf[]) | 按字符数组长度读取 |
示例如下:
try(
//初始化字符读取流
FileReader frd = new FileReader("ikun.txt");
){
//定义一个可变字符串对象
StringBuilder sbd = new StringBuilder();
//定义缓冲字符数组
char[] chars = new char[5];
int hasRead = 0; //读取到的字符长度
while((hasRead = frd.read(chars))>0){
sbd.append(new String(chars,0,hasRead));
}
//输出文件内容
System.out.println("文件全部内容:\n"+sbd.toString());
System.out.println("文件读取成功!");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
2.2.4 字符输出流
初始化如下:
FileWriter(String fileName)
FileWriter(File file, boolean append)
FileWriter(String fileName, boolean append)
其含义同字节输出流函数。
示例如下:
try( FileWriter fwr= new FileWriter("D:/test/test2.txt")){
//定义写入文件
String string = "KH96,正在学习字符流写入文件";
//直接写入目标文件
fwr.write(string);
//刷新缓冲区
fwr.flush(); //一定要刷新缓冲区
System.out.println("字符流写入成功!!!");
}catch (Exception e){
e.printStackTrace();
}
3. 匿名
3.1 lambda表达式
java中的 lambda
表达式的一般格式如下:
(参数列表) -> {lambda表达式体}
lambda
表达式的情况可分为以下几种:
-
无参数,无返回值
Runnable run = () -> {System.out.println("lambda表达式实现");};
如果执行语句只有一行,可以省略”{}“:
Runnable run = () -> System.out.println("lambda表达式实现");
-
有一个参数,无返回值
Consumer<String> consumer = (String s) -> {System.out.println(s);};
参数类型可以省略,因为编译器会根据上下文环境推断出参数的类型,也叫做类型推断。这里指定了泛型为String。
而且只有一个参数时,参数列表的”()“也可以省略。所以可以这么写:
Consumer<String> consumer = s -> System.out.println(s);
-
有多个参数,有返回值
Comparator<Integer> comparator1 = (o1,o2) -> { System.out.println(o2); return Integer.compare(o1,o2); };
-
只有一条执行语句且有返回值
Comparator<Integer> comparator1 = (o1,o2) -> { return Integer.compare(o1,o2); };
如果有返回值时只有一条执行语句,那么”return“可以省略。
Comparator<Integer> comparator1 = (o1,o2) -> Integer.compare(o1,o2);
-
将Lambda表达式作为参数传递
Thread thread = new Thread(() -> { System.out.println("lambda表达式实现"); });
为了将Lambda 表达式作为参数传递,接收Lambda 表达式的参数类型必须是与该Lambda 表达式兼容的函数式接口的类型。比如上面代码中的Lambda表达式的作用就是创建了一个Runnale对象,而new Thread()的参数可以是一个Runnable对象。文章来源:https://www.toymoban.com/news/detail-684305.html
3.2 方法引用
方法引用可以看做是lambda函数的语法糖,其引用与Lambda表达式对应如下:文章来源地址https://www.toymoban.com/news/detail-684305.html
类型 | 方法引用 | Lambda表达式 |
---|---|---|
Class::staticMethod |
(args) -> Class.staticMethod(args) |
|
实例方法引用 | Instance::instanceMethod |
(args) -> Instance.instanceMethod(args) |
对象方法引用 | Class::InstanceMethod |
(instance, args) -> Class.instanceMethod(args) |
构造方法引用 | Class::new |
(args) -> new Class(args) |
到了这里,关于Java注解、文件IO以及匿名函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!