java8增加了不少新特性,下面就一些常见的新特性进行学习。。。
1、接口中的方法
2、函数式接口
3、Lambda表达式
4、java8内置的四大核心函数式接口
5、方法引用和构造器引用
6、Stream API
7、并行流和串行流
8、Optional 类
9、新的时间与日期API
一:接口中的方法
在之前,接口中的方法都是抽象方法,默认被public abstract修饰,没有方法体。接口中的成员变量都是常量。
(1)接口中的静态方法
package com.bjsxt.testInterface; import sun.plugin2.os.windows.FLASHWINFO; /** * Created by Administrator on 2019/3/5. * 接口中使用static修饰的方法必须有方法体 * 接口中使用static修饰的方法只能被接口本身调用。 接口名.方法名(...) * 接口中的static方法不能被子接口继承 * 接口中的static方法不能被实现类重写或者直接调用 */ public interface Fly { //接口中的抽象方法 void air(); //接口中的静态方法,有方法体 static void wings(){ System.out.println("有翅膀。。。。。可以飞"); } } interface FlyChildren extends Fly{ } class Bird implements Fly{ @Override public void air() { System.out.println("鸟飞翔需要空气。。。"); } } class Test{ public static void main(String[] args){ Fly.wings(); //接口调用接口中的静态方法 FlyChildren.wings(); //报错,无法调用 Bird bird=new Bird(); bird.wings(); //报错,无法调用 } }
(2)接口中default修饰的方法
注意:接口默认方法的”类优先”原则
若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。接口冲突。如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突
package com.bjsxt.testInterface; import sun.plugin2.os.windows.FLASHWINFO; /** * Created by Administrator on 2019/3/5. * 接口中使用default修饰的方法必须有方法体 * 接口中使用default修饰的方法不能被接口本身调用。 * 接口中的default方法可以被子接口继承 * 接口中的default方法可以被实现类重写或者直接调用 */ public interface Fly { //接口中的抽象方法 void air(); //接口中default修饰的方法,有方法体 default void wings(){ System.out.println("有翅膀。。。。。可以飞"); } } interface FlyChildren extends Fly{ } class Bird implements Fly{ @Override public void air() { System.out.println("鸟飞翔需要空气。。。"); } // @Override // public void wings() { // System.out.println("鸟儿有翅膀,可以飞......"); // } } class Test{ public static void main(String[] args){ Bird bird=new Bird(); bird.wings(); //此时调用的是接口中的方法 } }
二:函数式接口
有且仅有一个抽象方法,但是可以有很多个非抽象方法的接口就是函数式接口,函数式接口可以被隐式转换为lambda表达式,函数式接口上面可以加个
@FunctionalInterface注解
@FunctionalInterface public interface Fly { //接口中的抽象方法 void air(); //接口中default修饰的方法,有方法体 default void wings(){ System.out.println("有翅膀。。。。。可以飞"); } }
三、Lambda表达式
Lambda 表达式需要“函数式接口”的支持(感觉就是对匿名内部类的简化)
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface 修饰可以检查是否是函数式接口
Lambda 表达式的基础语法:Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符箭头操作符将 Lambda 表达式拆分成两部分:
左侧:Lambda 表达式的参数列表
右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
package com.bjsxt.testInterface; /** * Created by Administrator on 2019/3/5. */ public interface TestInterface { int sum(int num1,int num2); } class Test{ public static void main(String[] args){ test3(); } public static void test1(){ //使用匿名内部类的写法 TestInterface testInterface=new TestInterface() { @Override public int sum(int num1, int num2) { return num1+num2; } }; System.out.println(testInterface.sum(10,20)); } public static void test2(){ //lambda写法1,常规写法 TestInterface testInterface=(int num1, int num2)->{ return num1+num2; }; System.out.println(testInterface.sum(10,20)); } public static void test3(){ /* * lambda写法2,简略写法 * 形参的数据类型可以省略掉,jvm虚拟机会根据上下文自动推断(类型推断),如果只有一个参数()也可以省略掉 * 如果方法体中的代码只有一行,{}可以省略掉,如果是return返回数据的,return也可以省略掉 **/ TestInterface testInterface=(num1, num2)->num1+num2; System.out.println(testInterface.sum(10,20)); } }
案例:
package com.bjsxt.lambda; /** * Created by Administrator on 2019/3/6. * 函数式接口 */ @FunctionalInterface public interface MyFunction { Integer getValue(Integer num); }
package com.bjsxt.lambda; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * Created by Administrator on 2019/3/6. */ public class TestLambda01 { public static void main(String[] args){ int aa=test1(100,(num)->{return num*num;}); } public static Integer test1(Integer num,MyFunction myFunction){ return myFunction.getValue(num); } }
四、java8内置的四大核心函数式接口
Java8 内置的四大核心函数式接口
Consumer<T> : 消费型接口
void accept(T t); //抽象方法
Supplier<T> : 供给型接口
T get(); //抽象方法
Function<T, R> : 函数型接口
R apply(T t); //抽象方法
Predicate<T> : 断言型接口
boolean test(T t); //抽象方法
package com.bjsxt.lambda; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import java.util.function.Supplier; /** * Java8 内置的四大核心函数式接口 * * Consumer<T> : 消费型接口 * void accept(T t); * * Supplier<T> : 供给型接口 * T get(); * * Function<T, R> : 函数型接口 * R apply(T t); * * Predicate<T> : 断言型接口 * boolean test(T t); */ public class TestLambda02 { public static void main(String[] args){ test1("helloWorld",str->System.out.println(str)); List list=test2(()->(int)(Math.random()*100)); list.forEach(System.out::print); } /** * 测试消费型接口 * @param str */ public static void test1(String str,Consumer<String> consumer){ consumer.accept(str); } /** * 测试供给型接口 */ public static List<Integer> test2(Supplier<Integer> supplier){ List<Integer> list=new ArrayList<>(); for(int i=0;i<10;i++){ list.add(supplier.get()); } return list; } }
其他两个接口也是同样,不再测试,还有其他一些内置的子接口,都是同样的用法
五、方法引用和构造器引用
package com.bjsxt.lambda; import java.io.PrintStream; import java.util.function.*; /** * 一、方法引用:若 Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用 * (可以将方法引用理解为 Lambda 表达式的另外一种表现形式) * 1. 对象的引用 :: 实例方法名 * 2. 类名 :: 静态方法名 * 3. 类名 :: 实例方法名 * 注意: * ①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致! * ②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式:类名 :: 实例方法名 * * 二、构造器引用 :构造器的参数列表,需要与函数式接口中参数列表保持一致! * 1. 类名 :: new * * 三、数组引用 * 类型[] :: new; */ public class TestLambda03 { public static void main(String[] args){ // test1(); test2(); } /** * 方法引用 * 对象的引用 :: 实例方法名 */ public static void test1(){ Consumer<String> consumer=str->System.out.println(str); //原来的写法 consumer.accept("hello world"); PrintStream ps=System.out; Consumer<String> consumer1=ps::println; //现在写法 consumer1.accept("hello world2"); System.out.println("---------------------------------------"); Student stu=new Student(1,"段然涛",24); Supplier<String> supplier=()->stu.getName(); //原来写法 System.out.println(supplier.get()); Supplier<String> supplier2=stu::getName; //现在写法 System.out.println(supplier.get()); } /** * 方法引用 * 类名 :: 静态方法名 */ public static void test2(){ BiFunction<Integer,Integer,Integer> biFunction=(x,y)->Math.max(x,y); //以前的写法 System.out.println(biFunction.apply(3,4)); BiFunction<Integer,Integer,Integer> biFunction2=Math::max; //现在的写法 System.out.println(biFunction2.apply(6,5)); } /** * 方法引用 * 类名 :: 实例方法名 */ public static void test3(){ BiPredicate<String, String> bp = (x, y) -> x.equals(y); //以前写法 System.out.println(bp.test("abx","abx")); BiPredicate<String, String> bp2=String::equals; //现在写法 System.out.println(bp.test("abx","abx")); } /** * 构造器引用 * 类名 :: new */ public static void test4(){ Supplier<Student> supplier=()->new Student(2,"李飞宇",34); //以前写法 System.out.println(supplier.get()); Supplier<Student> supplier2=Student::new; //现在写法,用的是无参的构造函数,因为该函数式接口里面的抽象方法是无参的 System.out.println(supplier.get()); BiFunction<Integer,String,Student> biFunction=Student::new; //用的是两个参数的构造函数 System.out.println(biFunction.apply(3,"阿飞")); } /** * 数组引用 * 类型[] :: new; */ public static void test5(){ Function<Integer,String[]> function=(num)->new String[num]; //以前的写法 System.out.println(function.apply(10)); Function<Integer,String[]> function2=String[]::new; //现在写法 System.out.println(function2.apply(10)); } } class Student{ public int id; public String name; public int age; public Student() { } public Student(int id, String name) { this.id = id; this.name = name; } public Student(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }