一、JDK8新特性
接口中默认方法+静态方法
− 默认方法就是一个在接口里面有了一个实现的方法。静态方法就是接口中有个已经使用的静态方法,可直接调用
Lambda 表达式(拉姆达)
− Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。方法引用 (Method Reference)− 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
// 方法引用的代码 System.out.println() ---> System::println();
Stream
API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
Date Time API
− 加强对日期与时间的处理。
二、关于接口的新特性
以前接口其中一个重要特性是: 其中的方法全都是抽象方法,即都没有方法体
JDK8以后,允许
接口中有被default和static修饰的方法带方法体
// 接口
public interface USB {
public static final int LENGTH = 1;
public abstract void chuanshu();
/**
* 使用default修饰方法,可以带方法体,即不再是抽象方法
* ----
* 子类实现接口,不用强制重写这个方法
* 子类对象可以调用该方法执行的
* ----
* 为什么这么设计这种语法?
* 这样设计,在大项目中,给父接口设计方法,所有子类无感,不用强制重写
* 个别子类有需要时,重写即可!!
*
*/
public default void show1() {
System.out.println("接口中的默认方法..." );
}
/**
* jdk8后,允许static修饰的方法带方法体
* 子类不能重写,也不调用
* 通过接口名直接调用静态方法
*/
public static void show2(){
System.out.println("接口中的静态方法..." );
}
}
// 子类
public class UDisk implements USB{
@Override
public void chuanshu() {
System.out.println("U盘传输数据" );
}
// 子类可以重写default方法
// 子类不能重写static方法
}
// 测试
public class TestUSB {
public static void main(String[] args) {
UDisk uDisk = new UDisk( );
uDisk.chuanshu();
uDisk.show1(); // 子类调用default方法
USB.show2(); // 接口调用静态方法
}
}
三、Lambda表达式[重点]
Lambda是匿名内部类的简化
Lambda 允许把函数(方法)作为一个方法的参数(函数作为参数传递到方法中)。
其实就是简化了匿名内部类的写法,更准确的说是对接口方法的重写的简化
3.1 初识lambda
使用lambda改写创建线程的方式
public class Demo1 {
public static void main(String[] args) {
new Thread(new Runnable( ) {
@Override
public void run() {
for (int i = 0; i < 10001; i++) {
System.out.println("正常实现Runnable完成线程" + i);
}
}
}).start( );
// 改成lambda形式
// lambda是简化了匿名内部类,只剩下关于方法的参数列表和方法体
// () -> {}
new Thread(() -> {
for (int i = 0; i < 10001; i++) {
System.out.println("lambda完成线程"+i);
}
}).start( );
// lambda是将方法当参数传递给另外一个方法
}
}
3.2 语法特点
能够写成lambda形式的的前提是
方法得有参数
参数的必须是接口
接口中的方法有且只能有一个!!!
总结: lambda就是对接口的抽象方法重写实现 例如: Thread(Runable run) 这个构造方法 1)Thread构造方法有参数 2)参数Runnable是接口 3)且Runnable接口内只有一个方法run 所以可以给这个Thread()构造方法内的代码改写成lambda形式
语法特征
(参数) -> {执行语句} 或者 参数 -> 执行语句
参数圆括号,当参数是一个的时候,圆括号可加可不加
(x) -> System.out.println(x)
x -> System.out.println(x)
参数圆括号,当参数是多个的时候,圆括号必须加
(x,y) -> System.out.println(x+y)
参数数据类型可写可不写,编译时会自动推断是什么类型
(x,y) -> System.out.println(x+y)
(int x,String y) -> System.out.println(x+y)
执行语句的花括号,当且仅当执行语句只有一句时,可以不加花括号
new Thread(() -> System.out.println("匿名内部类开启线程")).start();执行语句的花括号,当执行语句不只一句时,必须加花括号
new Thread(() -> { int a = 1; a++; System.out.println("lambda开启线程" ); }).start();关于返回值
如果方法有返回值,且执行语句只有一行语句时,可以不用写return,直接写值
test(() -> {return 1;}); test(() -> 1);// 1就是return1
如果代码比较多,又要返回数据,就必须写上return
test(() -> { int a = 1; a++; return a; });
public class Demo2 {
public static void main(String[] args) {
// 如果lambda方法体中只有一行代码,{}可以省略
show1(() -> System.out.println("lambda实现"));
show1(() -> {
System.out.println("lambda实现1");
System.out.println("lambda实现2");
System.out.println("lambda实现3");
}
);
// 当接口方法参数列表只有一个参数时,改写成lambda可以省略
// 1) 数据类型可以省略
// 2) 只有一个参数时,()可以省略
show2((b) -> System.out.println(b * 10 ));
show2(b -> System.out.println(b * 10 ));
// 当接口方法参数不止一个时,改成lambda时()不能省略
// 但是数据类型可以省略
show3((b,c) -> System.out.println(b + c ));
// lambda中方法体内,如果只有一行代码,{}和return都可以省略
show4((x,y) -> x+y);
show4((x,y) -> {
int c = x*y;
return c;
});
}
public static void show1(IA ia) {
ia.a( );
}
public static void show2(IB ib) {
ib.b(10);
}
public static void show3(IC ic) {
ic.c(10,"aaa");
}
public static void show4(ID id) {
id.d(10,10);
}
}
/**
* 使用lambda的前提
* 1) 方法有参数 2) 参数是接口 3)接口中有且只有一个方法
*/
interface IA {
void a();// 无参无返回值
}
interface IB {
void b(int b);
}
interface IC {
void c(int b,String c);
}
interface ID {
int d(int b,int c);
}
深入理解lambda,
为什么lambda要设计成,将方法(功能) 当参数传递给方法
有了lambda,方法的功能不再局限,方法具体如何,要看看lambda功能如何
public class Demo3 {
public static void main(String[] args) {
double add = add(1, 2);
System.out.println("add = " + add);
double yunsuan = yunsuan((x, y) -> x / y, 1, 2);
System.out.println("yunsuan = " + yunsuan);
}
/**
* 已经的方法,参数列表是普通变量
* 方法功能已经定好,唯一变化的是参数的值
* 例如,这个add方法,是做两数相加,只能相加
* 唯一能变的是,加的数不一样
* --------------------------
* 那如果,我想传入两个参数,让其相除返回结果?让其相乘返回结果?
* 就需要重新设计方法
*/
public static double add(int a,int b){
return a + b;
}
/**
* 有了lambda之后,方法的执行功能就不再固定
* 如何运行,要看调用时,传入的lambda是如何运行的
*/
public static double yunsuan(IE e,int a,int b){
return e.jisuan(a, b);
}
}
interface IE {
double jisuan(int a,int b);
}
3.3 练习
// 使用lambda改写创建线程
new Thread(() -> {
for (int i = 0; i < 10001; i++) {
System.out.println("lambda完成线程"+i);
}
}).start( );
// 使用lambda改写创建线程池的方式
// 使用lambda改写创建TreeSet指定比较器的方式
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(
3,
10,
10,
TimeUnit.MINUTES,
new ArrayBlockingQueue<Runnable>(10)
);
// execute方法内改写成lambda即可
pool.execute( () -> {
for (int i = 0; i < 11; i++) {
System.out.println("线程执行" );
}
} );
pool.shutdown();
// 使用lambda改写TreeSet
// 以前是使用匿名内部类完成实现Comparator接口重写方法
// 现在使用lambda可以简化重写的步骤
TreeSet<Integer> set = new TreeSet<>((o1,o2) -> o2 - o1);
set.add(1);
set.add(3);
set.add(2);
set.add(5);
set.add(4);
System.out.println(set );
}
3.4 总结
lambda就是简化了匿名内部类的写法
lambda其实就是接口方法的重写
lambda的参数和返回值是根据接口方法决定的