1.JDK8中接口的新增
在JDK8中针对接口有做增强,在JDK8之前
interface 接口名{
静态常量;
抽象方法;
}
JDK8之后对接口做了增加,接口中可以有默认方法和静态方法
interface 接口名{
静态常量;
抽象方法;
默认方法;
静态方法;
}
2.默认方法
2.1 为什么要增加默认方法
在JDK8以前接口中只能有抽象方法和静态常量,会存在以下的问题:
如果接口中新增抽象方法,那么实现类都必须要抽象这个抽象方法,非常不利于接口的扩展的
举个例子:
接口
interface A{
void test1();
// 接口中新增抽象方法,所有实现类都需要重写这个方法,不利于接口的扩展
void test2();
}
两个接口的实现类
class B implements A{
@Override
public void test1() {
}
@Override
public void test2() {
}
}
class C implements A{
@Override
public void test1() {
}
@Override
public void test2() {
}
}
主启动类:
package com.bobo.jdk.inter;
public class Demo01Interface {
public static void main(String[] args) {
A a = new B();
A c = new C();
}
}
2.2 接口默认方法的格式
接口中默认方法的语法格式是
interface 接口名{
修饰符 default 返回值类型 方法名{
方法体;
}
}
接口的第三个方法是默认方法:
interface A{
void test1();
// 接口中新增抽象方法,所有实现类都需要重写这个方法,不利于接口的扩展
void test2();
/**
* 接口中定义的默认方法
* @return
*/
public default String test3(){
System.out.println("接口中的默认方法执行了...");
return "hello";
}
}
在接口的实现类中默认方法可以不强制重写实现,也可以重写实现
class B implements A{
@Override
public void test1() {
}
@Override
public void test2() {
}
@Override
public String test3() {
System.out.println("B 实现类中重写了默认方法...");
return "ok ...";
}
package com.bobo.jdk.inter;
public class Demo01Interface {
public static void main(String[] args) {
A a = new B();
a.test3();
A c = new C();
c.test3();
}
}
}
2.3接口中的默认方法有两种使用方式
3.静态方法
JDK8中为接口新增了静态方法,作用也是为了接口的扩展
3.1 语法规则
接口的静态方法格式:
interface 接口名{
修饰符 static 返回值类型 方法名{
方法体;
}
}
举个例子:
接口:
interface A{
void test1();
// 接口中新增抽象方法,所有实现类都需要重写这个方法,不利于接口的扩展
void test2();
/**
* 接口中定义的默认方法
* @return
*/
public default String test3(){
System.out.println("接口中的默认方法执行了...");
return "hello";
}
/**
* 接口中的静态方法
* @return
*/
public static String test4(){
System.out.println("接口中的静态方法....");
return "Hello";
}
}
接口实现类:
class B implements A{
@Override
public void test1() {
}
@Override
public void test2() {
}
@Override//这个是接口实现类的默认方法的重载
public String test3() {
System.out.println("B 实现类中重写了默认方法...");
return "ok ...";
}
}
class C implements A{
@Override
public void test1() {
}
@Override
public void test2() {
}
}
3.2 静态方法的使用
接口中的静态方法在实现类中是不能被重写的,调用的话只能通过接口类型来实现: 接口名.静态方法名
();
函数式接口
1.1 函数式接口的由来
我们知道使用Lambda表达式的前提是需要有函数式接口,
而Lambda表达式使用时不关心接口名,抽象方法名。只关心抽象方法的参数列表和返回值类型。
因此为了让我们使用Lambda表达式更加的方法,在JDK中提供了大量常用的函数式接口。
举个例子:
package com.bobo.jdk.fun;
public class Demo01Fun {
public static void main(String[] args) {
fun1((arr)->{//此处的lambda表达式参数是arr数组
int sum = 0 ;
for (int i : arr) {
sum += i;
}
return sum;
});
}
public static void fun1(Operator operator){
int[] arr = {1,2,3,4};
int sum = operator.getSum(arr);
System.out.println("sum = " + sum);
}
}
/**
* 函数式接口
*/
@FunctionalInterface
interface Operator{
int getSum(int[] arr);
}
1.2@FunctionalInterface注解(带有这个注解的接口是函数式接口)
/**
* @FunctionalInterface
* 这是一个标志注解,被该注解修饰的接口只能声明一个抽象方法
*/
@FunctionalInterface
public interface UserService {
void show();
}
2 函数式接口介绍
在JDK中帮我们提供的有函数式接口,主要是在 java.util.function 包中。
2.1 Supplier
无参有返回值的接口,对于的Lambda表达式需要提供一个返回数据的类型。
Supplier接口:
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();//这个是lambda关注
}
使用:
/**
* Supplier 函数式接口的使用
*/
public class SupplierTest {
public static void main(String[] args) {
fun1(()->{//lambda表达式
int arr[] = {22,33,55,66,44,99,10};
// 计算出数组中的最大值
Arrays.sort(arr);
return arr[arr.length-1];//返回值
});
}
private static void fun1(Supplier<Integer> supplier){//先要声明一个方法来用接口
// get() 是一个无参的有返回值的 抽象方法
Integer max = supplier.get();//用到了接口的抽象方法
System.out.println("max = " + max);
}}
2.2 Consumer
有参无返回值得接口
前面介绍的Supplier接口是用来生产数据的,而Consumer接口是用来消费数据的,使用的时候需要指定一个泛型来定义参数类型
Consumer 接口:
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);//接口的抽象方法,lambda关注的重点
}
使用:
public class ConsumerTest {
public static void main(String[] args) {
test(msg -> {//有参,参数是Hello World
System.out.println(msg + "-> 转换为小写:" + msg.toLowerCase());
});
}
public static void test(Consumer<String> consumer){//声明一个方法,来用comsumer接口
consumer.accept("Hello World");//在方法内用接口的抽象方法
}
}
2.3 Function
有参有返回值的接口,
Function接口是根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。有参数有返回值。
Function接口:
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);//接口的抽象方法,lambda关注的重点,有参数T t,有返回值R
}
运用:
public class FunctionTest {
public static void main(String[] args) {
test(msg ->{//lambda表达式,msg是test方法中字符串
return Integer.parseInt(msg);
});
}
public static void test(Function<String,Integer> function){//先声明一个方法,用到接口
Integer apply = function.apply("666");//接口的抽象方法,接口中的字符串是前提条件,也就代表参数是字符串类型的
System.out.println("apply = " + apply);
}
}
2.4 Predicate
有参且返回值为Boolean的接口
Predicate接口:
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);//接口的抽象方法,lambda关注的重点,有参数T t,有返回值
}
运用:
public class PredicateTest {
public static void main(String[] args) {
test(msg -> {//msg是参数,值是后面的那个字符串HelloWorld,这个是test方法中
return msg.length() > 3;
},"HelloWorld");
}
private static void test(Predicate<String> predicate,String msg){//先声明一个方法,用到接口
boolean b = predicate.test(msg);//接口的抽象方法
System.out.println("b:" + b);
}
}
方法引用
01 lambda表达式冗余
在使用Lambda表达式的时候,也会出现代码冗余的情况,比如:用Lambda表达式求一个数组的和
package com.bobo.jdk.funref;
import java.util.function.Consumer;
public class FunctionRefTest01 {
public static void main(String[] args) {
printMax(a->{
// Lambda表达式中的代码和 getTotal中的代码冗余了
int sum = 0;
for (int i : a) {
sum += i;
}
System.out.println("数组之和:" + sum);
});
}
/**
* 求数组中的所有元素的和
* @param a
*/
public void getTotal(int a[]){
int sum = 0;
for (int i : a) {
sum += i;
}
System.out.println("数组之和:" + sum);
}
private static void printMax(Consumer<int[]> consumer){
int[] a= {10,20,30,40,50,60};
consumer.accept(a);
}
}