Lambda表达式
lambda表达式是JDK8的新特性,它允许代码块作为方法参数,通过lambada表达式我们可以以更加简洁的方式创建只有一个抽象方法的接口(函数式接口)实例,它的出现极大的简化了匿名内部类的实现方式,一个lambda表达式主要由三部分构成:形参列表、箭头符号和代码块。
函数式接口
所谓函数式接口就是指只包含有一个抽象方法的接口,当然它可以有任意多个默认方法和静态方法,在JDK1.8中使用@FunctionalInterface注解来表明该接口是函数式接口,使用此注解的目的就是强制编译器检查该接口是否满足函数式接口的条件,关于注解的使用我们在后续的文章中另行讨论。
形参列表
lambda的形参列表如果只包含一个形参时可以省略参数类型和圆括号,如果包含有一个以上形参时,参数类型可以省略,程序会自动推算出形参的类型,这其实就是一种语法糖。
代码块
lambda的代码块如果只包含一句代码时,可以省略花括号,如果有返回值时,可以省略return子句,程序会自动将该句代码的运算结果作为返回值返回。
定义语法
(形参列表) -> {
//代码块
}
栗子
package com.icypt.lambda;
interface InterA {
//无参抽象方法
public void methodA();
}
interface InterB {
//有参抽象方法
public void methodB(String txt);
}
interface InterC {
//有参有返回值抽象方法
public int mechodC(int a, int b);
}
interface InterD {
//有参有返回值抽象方法
public int mechodD(int a, int b);
}
/**
*运行结果:
*Hello icypt!
*传入的参数值:冰点IT公众号,一个用心分享IT技术的公众号!
*打印计算结果值500
*打印计算结果值30
*/
public class LambdaExp {
//用主方法测试
public static void main(String[] args) {
LambdaExp lambdaExp = new LambdaExp();
//lambda表达式只有一条语句,省略花括号
InterA interA = () -> System.out.println("Hello icypt!");
interA.methodA();
//lambda表达式只有一条语句,带参数,无返回值
InterB interB = txt -> System.out.println("传入的参数值:" + txt);
String txt = "冰点IT公众号,一个用心分享IT技术的公众号!";
interB.methodB(txt);
//lambda表达式只有一条语句,带参数,有返回值
InterC interC = (a, b) -> (a*a + b*b);
System.out.println("打印计算结果值" + interC.mechodC(10, 20));
//lambda表达式只有多条语句,带参数,有返回值
InterD interD = (a, b) -> {
int sum = a + b;
int ll = sum * 2;
return ll;
};
System.out.println("打印计算结果值" + interD.mechodD(5, 10));
}
}
通过以上栗子我们发现其实lambda表达式返回的结果就是一个函数式接口的匿名对象,而对于lambda表达式本身其实就是对接口抽象方法的实现,不过这种实现是一种匿名的实现方式。
Lambad代码块简易语法
上述我们讨论过当lambda表达式代码块为一句代码时可以省略花括号,其实它还有更加风骚的语法,不过要依赖于这句代码的调用场景而定。如果此句代码为某一个类调用其静态方法,则使用“类名称::方法名称”的方式编写,函数式接口参数全部作为静态方法参数;如果此句代码为某一个类对象调用其方法,则使用“类名称::对象方法”的方式编写,其函数式接口参数的第一参数作为调用者,其他参数全部作为对象方法参数;如果此句代码为某一个类的构造方法,则使用"类名称::new"的方式编写,函数式接口参数全部作为构造方法参数。
栗子
package com.icypt.lambda;
interface InterA {
public String methodA();
}
interface InterB {
public void methodB(LambdaExpX lambdaExpX, String txt);
}
interface InterC {
public LambdaExpX mechodC(String a, String b);
}
/**
*运行结果:
*我是静态方法
*Hello World
*Hello*******world
*/
public class LambdaExpX {
private String a;
private String b;
public LambdaExpX() {}
public LambdaExpX(String a, String b) {
this.a = a;
this.b = b;
}
public static String getMsg() {
return "我是静态方法";
}
public void print(String txt) {
System.out.println(txt);
}
public String toString() {
return this.a + "*******" + this.b;
}
//用主方法测试
public static void main(String[] args) {
//调用静态方法
InterA intera = LambdaExpX::getMsg;
String msg = intera.methodA();
System.out.println(msg);
//调用实例方法
InterB interb = LambdaExpX::print;
interb.methodB(new LambdaExpX(), "Hello World");
//调用构造方法
InterC interc = LambdaExpX::new;
LambdaExpX lambdaExpX = interc.mechodC("Hello", "world");
System.out.println(lambdaExpX);
}
}
以上的简易编写虽然华丽但是代码语义并不明确,还是建议大家采用传统的lambda表达式方式进行编写。
垃圾回收机制
对象存在的三种状态
一个对象从创建之初到被销毁,大致存在三种状态:分别是可达状态,此时的对象可以操作对象成员,改变对象状态;可恢复状态,此时的对象已经没有引用指向它了,它的状态已经满足垃圾回收的条件了,当垃圾回收器在回收此对象时,先会调用其finalize方法,在此方法中该对象还可以重新为自己获得引用;不可达状态,执行了finalize方法之后该对象还是没有恢复到可达状态,那么该对象就变为不可达状态,等待垃圾回收器回收,如下图。
垃圾回收机制(自动)
在之前对象的使用中我们分析过当一个对象创建时,系统会在堆内存中开辟一块空间用来保存这个对象,同时也会在栈内存开辟一块空间用来保存该对象的引用,如果该引用被置为null或者指向了其他对象,那么它原来所指向的对象如果不再有新的引用指向的话,这个原来的对象就会成为垃圾对象,等待垃圾回收器来回收。垃圾回收器只会回收运行时数据区(堆内存)中的已经永久失去引用的对象,它的回收时机是不确定的,在该对象被回收之前总会调用其finallize方法,该方法的主要作用是做一些垃圾回收前的清理操作,
当然我们也可以在这个方法中让一个对象从可恢复状态恢复成可达状态,这种垃圾回收的方式是一种系统自发的回收机制,当然我们也可以手动触发;
栗子
package com.icypt.gc;
public class GcFinalizeAuto {
// 对象被回收之前执行
public void finalize() throws Throwable {
System.out.println("我要被回收了哦!");
}
public static void main(String[] args) {
for(int i=0; i <10000000; i++) {
new GcFinalizeAuto();
}
}
}
手动回收机制
所谓手动回收机制是开发人员在编码的过程中在需要垃圾回收的地方手动调用垃圾回收器,这种行为虽然看起来是强制的,但是对于JVM来说只会把这种行为当成一种建议,至于何时执行,还是不确定的,但是加了手动回收的代码后往往还是起一定的作用的,Java中为我们提供了两种手动调用垃圾回收的方式:
1、通过System类的静态方法gc即:System.gc();
2、通过Runtime类的实例方法gc即:Runtime.getRuntime().gc();
栗子
package com.icypt.gc;
public class GcFinalizeHand{
//被回收时触发
public void finalize() throws Throwable {
System.out.println("我要被回收了,还有啥要说的没?");
}
public static void main(String[] args) {
GcFinalizeHand gcFinalizeHand = new GcFinalizeHand();
gcFinalizeHand = null;
//两种手动回收方式
//手动回收方式一
//System.gc();
//手动回收方式二
Runtime.getRuntime().gc();
}
}
栗子,在finalize方法中让可恢复状态的对象变成可达状态
package com.icypt.gc;
public class GcFinalizeReset{
public static GcFinalizeReset gcFinalizeReset = null;
//被回收时触发
public void finalize() throws Throwable {
System.out.println("我要被回收了,我还想存在一会儿");
gcFinalizeReset = this;
}
public void printMsg() {
System.out.println("冰点IT,666666666666666666666!");
}
public static void main(String[] args) {
gcFinalizeReset = new GcFinalizeReset();
gcFinalizeReset = null;
//两种手动回收方式
//手动回收方式一
//System.gc();
//手动回收方式二
Runtime.getRuntime().gc();
//强制垃圾回收
Runtime.getRuntime().runFinalization();
gcFinalizeReset.printMsg();
}
}
Jar文件的使用
jar,java archive,中文意思是Java归档,其实就是一个压缩文件,它的压缩方式和zip的压缩方式相同,只是在生成jar包的时候系统会自动创建一个META-INF/
MANIFEST.MF的清单文件,用来描述jar文件的一些属性。我们可以通过JDK提供的jar命令生成jar文件,也可以使用一些常用的压缩工具来创建jar文件,只是在使用压缩工具创建jar文件时,记得手动添加清单文件。
jar命令用法
用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
选项:
-c 创建新档案
-t 列出档案目录
-x 从档案中提取指定的 (或所有) 文件
-u 更新现有档案
-v 在标准输出中生成详细输出
-f 指定档案文件名
-m 包含指定清单文件中的清单信息
-n 创建新档案后执行 Pack200 规范化
-e 为捆绑到可执行 jar 文件的独立应用程序
指定应用程序入口点
-0 仅存储; 不使用任何 ZIP 压缩
-P 保留文件名中的前导 '/' (绝对路径) 和 ".." (父目录) 组件
-M 不创建条目的清单文件
-i 为指定的 jar 文件生成索引信息
-C 更改为指定的目录并包含以下文件
栗子
::创建jar包命令
jar -cvf test.jar target\
::更新jar包命令,如果文件存在则是更新,否则是新增
jar -uvf test.jar target\C.class
::查看jar包文件结构
jar -tf test.
::解压jar包到当前文件夹
jar -xvf test.jar
::创建可执行jar包
jar -xvfe test.jar 主类完整类名称 需要压缩的*.class文件,可以使用通配符过滤
::执行可执行jar文件
java -jar jar文件名称
以上是一些常用的jar命令,其实还是非常有用的,建议大家记一下,那么如何使用命令引用一个jar文件呢?我们在之前讨论Java运行原理的时候说过,当我们需要引入第三方类库时,需要配置classpath环境变量,让编译命令执行的时候,JVM会去指定的路径下搜索类文件,这种方式比较适合项目的开发,如果是我们自己的打的jar文件,想要引用的话,其实只需在编译命令中增加-classpath参数即可,它的作用和环境变量是一样一样的但是它是临时的,cmd窗口关闭以后将失效,下次还是得重写输入,但是这种方式调试起来比较灵活,建议大家学习时可以以这种方式运行。
栗子,更新一下编译命令和执行命令
javac -d 编译文件存放路径 -classpath *.class文件的路径 -encoding 编码:utf-8|gb2312 源文件名称
cd 编译文件存放根路径
java 包.类名称
以上命令满足你使用了package关键字,import关键字亦或者是要使用jar文件,请大家稍作记忆。
至此,关于lambda表达式、垃圾回收机制以及jar文件的运用就讨论完了,下篇我们来看Java核心类库String类、Object类、Runtime类以及日期、时间、数学等工具类的使用。
java培训:http://www.baizhiedu.com/python2019