����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Java8
整型常量(JDK7.0之后)
在Java8中整型常量可以用下划线分隔表示,这样的目的是为了更方便阅读
int a = 100_000;
//下划线不能写在最开始的位置和最末尾的位置
//下划线不能写在小数点左右两边
int b = _10,c = 10_;
double d = 10._0,e = 10_.0;
I/O流的释放(jdk7.0之后)
为了简化代码并且不抛出异常,新增了IO流资源释放的方式,可以将流的定义创建写入到try()的括号中,就相当于作为这个方法的变量,这样可以减少异常的出现(例如空指针异常等)和简化代码,如果同时创建多个流需要用分号隔开,因为创建一个流就相当于一个语句。
try(FileOutputStream out =new FileOutputStream("A.txt");
FileInputStream in = new FileInputStream("A.txt")) {
byte[] buf = new byte[1024];
out.write("石原里美".getBytes());
in.read(buf);
System.out.println(Arrays.toString(buf));
in.close();
out.close();
} catch (Exception e) {
}
接口方法
在JDK1.8之后,接口中不仅只有抽象方法,还可以静态方法和默认方法,这是因为当我们已经实现了接口原本有的抽象方法之后,又新增了其他的方法,那么所有的实现类都要实现定义的新方法,这就带来了很多不便
接口目前已经逐渐趋势化于抽象类,这是因为抽象类拥有更多的功能,而实现类可以实现多个接口。
静态方法
interface A{
static void show() {
System.out.println("这是静态方法");
}
}
静态方法可以通过 接口名.方法名直接调用
接口中的静态方法不会被继承,也不能通过多态的性质进行访问
默认方法
interface A{
default void time() {
System.out.println("这是默认方法");
}
}
默认方法的优势
- 可以让接口更良好的升级,当有新的方法需要增加的时候i,可以减少开发人员的负担,不用在每一个实现类中重写方法,因为默认方法不需要重写就可以通过子类调用
- 减少没必要的空实现
如果一个实现类实现了两个接口,并且接口中有同一个静态方法,那么
- 当继承的父类和实现的接口中有相同签名的方法时,优先使用父类的方法。
- 当接口的父接口中也有同样的默认方法时,就近原则调用子接口的方法。
- 当实现的多个接口中有相同签名的方法时,必须在实现类中通过重写方法解决冲突问题,否者无法通过编译,在重写的方法中可以通过 接口名.super.方法名(); 的方式显示调用需要的方法。
public class Test {
public static void main(String[] args) {
A a = new B();
a.time();
}
}
interface A{
default void time() {
System.out.println("这是默认方法");
}
}
interface C extends A{
default void time() {
System.out.println("这是重写后的默认方法");
}
}
class D {
public void time() {
System.out.println("这是父类方法");
}
}
class B extends D implements A,C{
}
Lambda
Lambda表达式时Java8的新特性,可以支持函数式编程,个人感觉其作用主要就是简化代码,但需要函数式编程的思想,如果不是很有必要,用原来的方法也可以,不必学习Lambda,因为这并不会影响你写代码
首先要明白,方法不可以单独存在,而函数更不能单独存在。
行为参数化
作为一个开发人员,要明白需求不是固定的,这要取决于甲方爸爸,例如
public int time(int a) {
int sum = 0;
for(int i = 1;i <= a;i++) {
sum+=i;//核心执行代码
}
return sum;
}
public int show(int a) {
int sum = 0;
for(int i = 1;i <= a;i++) {
sum = (int) (sum == 0?sum+=1:sum*i);//核心执行代码
}
return sum;
}
这两个方法都是甲方的需求,但还有可能还会有更多类似的需求,而我们并不知道最终需求是哪个一个,那么就需要都写出来
但仔细观察就会发现,这两个方法除了方法名和核心行为代码不同以外,其他都相同
那么,其实我们就可以传一个核心行为到同一个方法中,这样就可以通过传入的不同行为实现不同的方法。
public int top(int a,核心行为代码) {
int sum = 0;
for(int i = 1;i <= a;i++) {
核心行为代码
}
return sum;
}
这种方法就是行为参数化,将核心行为操作抽象变成一个参数
需要注意的是,方法名只是一个标识符,通过标识符来确定调用的是哪一个方法,一个方法最关键的就是行为的操作代码
我们知道,在Java中是不允许有独立代码存在的-----核心行为代码,所以必须要依托于一个类。
public class Test {
public int time(int a) {
int sum = 0;
for(int i = 1;i <= a;i++) {
sum+=i;
}
return sum;
}
public int show(int a) {
int sum = 0;
for(int i = 1;i <= a;i++) {
sum = (int) (sum == 0?sum+=1:sum*i);
}
return sum;
}
public int calculate(int a,CoreBehavior c) {
int sum = 0;
for(int i = 1;i <= a;i++) {
sum = c.result(sum,a);
}
return sum;
}
public static void main(String[] args) {
new Test().calculate(10, new CoreBehavior() {
//求和
@Override
public int result(int a,int b) {
a += b;
return a;
}
});
}
}
interface CoreBehavior{
//核心行为
int result(int a,int b);
}
这就是将核心行为抽出来,这相当于之前是简化了不少代码,
但其实我们发现,每次调用还是需要编写较多的代码
每次我们都需要new对象的操作,还有对result方法的声明,但我们其实真正关心的其实就是三部分
- 方法的参数列表
- 方法中的核心操作代码
- 方法的返回类型
而函数式编程就是将创建匿名对象的过程,变成一个计算求值的过程,那么这个求值的表达式就是我们所谓的函数式编程,也就是所谓的Lambda表达式
public static void main(String[] args) {
new Test().calculate(10,(a,b)->a+=b);
}
//其中new Test().calculate(10,(a,b)->a+=b);是下面Lambda表达式更进一步的简写
//new Test().calculate(10,(int a,int b)->{
// return a+=b;
// });
- 其中()标识参数列表,
- ->后面跟的是函数主题
- {}函数主体,表达式的返回值,由这个函数主体中的代码来决定
Lambda表达式在Java中存在的意义就是作为一个接口的实现类对象
这个接口必须是函数式接口:该接口中有且仅有一个抽象方法,允许默认方法和静态方法的存在
针对于函数式接口,java8新增了一个注解@FunctionalInterface,用来检查该接口是不是一个函数式接口,如果不是,编译就会报错
函数式接口中,抽象方法常见的几种情况
-
抽象方法无参,无返回值
@FunctionalInterface interface CoreBehavior{ void result(); } public class Test { public static void main(String[] args) { //标准语法{}中放执行语句 CoreBehavior c = ()->{}; //如果只有一行执行语句 c = ()->System.out.println(); } }
-
抽象方法有参无返回值
@FunctionalInterface interface CoreBehavior{ void result(int a); } @FunctionalInterface interface Core{ void result(int a,String s); } public class Test { public static void main(String[] args) { //一个参数 //标准语法{}中放执行语句 CoreBehavior c = (int a)->{}; //简化 c = (a)->{}; //再简化,多个参数不可以这样写 c = a ->{}; //只有一行语句 c = a->System.out.println(a); //多个参数 //标准语句 Core o = (int a,String s)->{}; //简化 o = (a,s)->{}; //一行语句 o = (a,s)->System.out.println(a+s); } }
-
抽象方法无参,有返回值
@FunctionalInterface interface Core{ int result(); } public class Test { public static void main(String[] args) { //标准语法 Core c = ()->{ int a =1; return a; }; //简化,只有一行语句的时候 不写return c = ()->1; } }
-
抽象方法有参,有返回值
@FunctionalInterface interface CoreBehavior{ String result(int a,String s); } @FunctionalInterface interface Core{ int result(int a); } public class Test { public static void main(String[] args) { //一个参数 //标准语法 Core c = (int a)->{ a++; return a; }; //简化,只有一行语句 不写return c = a->a; //多个参数 //标准语法 CoreBehavior o = (int a,String s)->{ String b = a+s; return b; }; //简化,只有一行语句 不写return o = (a,s)->a+s; } }
在Lambda表达式中,参数列表里里面的参数可以不写类型,JVM会自动推断。
@FunctionalInterface
interface CoreBehavior{
String result(String s);
}
@FunctionalInterface
interface Core{
int result(int a,String s);
}
public class Test {
public void test1(CoreBehavior c) {
System.out.println(c.result("1"));
}
public void test1(Core c) {
System.out.println(c.result(1,""));
}
public static void main(String[] args) {
//调用的是CoreBehavior里面的方法
new Test().test1((a)->a);
}
}
当然也会有其他问题
@FunctionalInterface
interface CoreBehavior{
String result(String s);
}
@FunctionalInterface
interface Core{
int result(int a);
}
public class Test {
public void test1(CoreBehavior c) {
System.out.println(c.result("1"));
}
public void test1(Core c) {
System.out.println(c.result(1));
}
public static void main(String[] args) {
new Test().test1(a->a);//这行会编译报错,因为两个方法都满足
new Test().test1((Core)a->a);//进行类型转化就可以,明确调用的是哪个方法
}
}
还有一点需要注意的是
在Java8中,被匿名内部类,局部内部类,Lambda表达式访问的局部变量要么是一个常量,要么看起来像一个常量(只进行一次赋值)