一、接口定义加强
首先我们回顾一下之前学习过的接口。让它要求我们的接口只能够由抽象方法、全局常量组成。但是我们今天讲解一下接口里面除了这两种元素以外还可以有普通方法和static方法。但是这样的特性是在我们JDK1.8以后才有的。
1.可以使用default来定义普通方法,需要通过对象调用。
package com.wschase.interfaces;
/**
* Author:WSChase
* Created:2018/12/3
*/
//1.在接口中定义普通方法
//interface IMessage{
// //在接口中定义普通方法需要用到default这个关键字,但是它不表示
// //这个方法的权限是default,我们不违背前面所学内容,在interface中
// //只有public这个权限。
// public default void fun(){
// System.out.println("Heollo IMessage");
// }
// public void print();
//}
//class MessageImpl implements IMessage{
// @Override
// public void print() {
// System.out.println("Hello MessageImpl");
// }
//}
//public class TestDemo {
// public static void main(String[] args) {
// IMessage message = new MessageImpl();
// message.print();
// message.fun();
// }
//}
2.可以和类里面定义静态方法一样,使用static关键字修饰方法,定义静态方法,这个方法可以直接由接口名字调用。
//2.定义static方法
interface IMessage{
//定义了普通方法
public default void fun(){
System.out.println("Hello IMessage");
}
//静态方法就和类里面的静态方法相似,可以直接由(类名)接口名称调用
public static IMessage getInstance(){
return new MessageImpl();
}
public void print();
}
class MessageImpl implements IMessage{
@Override
public void print() {
System.out.println("Hello MessageImpl");
}
}
public class TestDemo{
public static void main(String[] args) {
IMessage message=IMessage.getInstance();
System.out.println(message);
message.print();
}
}
注意:学完这个新特性,我们需要知道,当在以后面对接口的认识这种类型的问题的时候,我们需要将这个新特性也告诉别人。
二、Lambda表达式
这个也是我们java在JDK1.8以后才有的新特性。之所以会出现Lambda表达式,是因为在我们的C语言是面向过程编程的,而我们的Java是面向对象编程的。所以我们的Lambda表达式是是函数式编程。
1.首先我们对比一下传统面向对象编程和函数式编程的区别:
面向对象编程:
package com.bittech.lambda;
/**
* Author:WSChase
* Created:2018/12/3
*/
interface IMessage{
public void print();
}
public class TestLamda {
public static void main(String[] args) {
//这是我们传统的面向对象的编程——>匿名对象实现接口并且创建对象
IMessage message=new IMessage() {
@Override
public void print() {
System.out.println("这是接口中的抽象方法");
}
};
message.print();
}
}
函数式编程:
//2.函数式编程
interface IMessage{
public void print();
}
public class TestLamda{
public static void main(String[] args) {
//函数式编程实现与上面一样的功能
IMessage message= () -> System.out.println("这是接口中的抽象方法");
message.print();
}
}
上面就是我们的Lambda表达式,它就是函数式编程。但是我们需要注意的是:我们的函数式编程由一个前提,接口必须只有一个方法,如果有两个方法那么将不能使用函数式编程。为了避免我们在定义接口的时候不知道我们这个接口是为了函数式编程,我们又有了一个新的注解:@FunctionlInterface。
//2.函数式编程
@FunctionlInterface
interface IMessage{
public void print();
}
public class TestLamda{
public static void main(String[] args) {
//函数式编程实现与上面一样的功能
IMessage message= () -> System.out.println("这是接口中的抽象方法");
message.print();
}
}
2.Lambda表达式语法
语法1:(参数)->单行语句;
语法2:(参数)->{};
例子:
////单行语句:
//interface IMessage{
// public void print();
//}
//public class TestLamda{
// public static void main(String[] args) {
// //函数式编程实现与上面一样的功能
// IMessage message= () -> System.out.println("这是接口中的抽象方法");
// message.print();
// }
//}
//多行语句:
//2.函数式编程
@FunctionalInterface
interface IMessage{
public void print();
}
public class TestLamda{
public static void main(String[] args) {
//函数式编程实现与上面一样的功能
IMessage message= () -> {
System.out.println("这是接口中的抽象方法");
System.out.println("Hello World");
};
message.print();
}
}
其实Lambda表达式,就是将方法和对象连接起来了。
//直接进行计算
@FunctionalInterface
interface IMath{
public int add(int x,int y);
}
public class TestLamda{
public static void main(String[] args) {
//函数是编程的使用,还是输出一句话
IMath msg= (p1, p2) -> p1+p2;
System.out.println(msg.add(10,20));
}
}
对于这个例子我们可以更加清楚的知道Lambda表达式的含义:首先左边的IMath msg是面向对象的,这是在实例化一个对象;右边这是在重写方法,相当于是函数,这是面向过程的,所以这样就很好的将函数式编程和对象式编程结合起来了。
使用Lambda表达式注意:
Lambda表达式:
有一个大前提:接口有且仅有一个抽象方法。
- 如果实现抽象方法中如果只有一条命令,大括号就可以省略。
- 如果抽象方法的参数只有一个的时候,参数列表的括号可以省略;连个参数不可以省略。
- 如果抽象方法实现中有返回值,并且之只有一个语句,那么这条语句的结果就是返回值。
- 标准写法:不简写。
Lambda表达式:(参数列表)->{实现内容};
eg:接口 对象名=(参数列表)->{实现内容};
注意:在Lambda表达式所在的作用域下防止参数列表中的名字作用与中的其他变量的名字重复。
5.注解:FunctionInterface是为了让我们的这个接口里面只有一个抽象方法。它会检查如果发现接口出现了多个抽象方法,那么就会报错。
三、方法引用
我们在之前的java学习中也有用到引用,但是只有数组、类、接口具备引用操作。这些都是可以实例化对象的。在JDK1.8以后追加了方法引用,其实引用就是起别名。
下面我们以类为例解释什么是引用:
(1)面向对象中调用方法有三种情况:
静态方法、普通方法、构造方法,对于它们的使用我们有不同的规则:
类名称.静态方法
实例化对象.普通方法
类名称.构造方法
方法引用就是将这些方法在使用的时候起一个别名,就相当于我们数学中的函数:
y=f(x):输入自变量x,返回函数y。<–类比于方法引用–>
(1)f(x)<=>类名称.静态方法(这是我们需要实现的)
(2)f()<=>类名称.静态方法()
(3)f(x)<=>类名称.静态方法(参数列表)
(4)y=f(x)<=>别名=类名称.静态方法(参数列表)
对于我们的函数f(x)它的别名就是y,而对于我们的方法引用,是将我们调用方法这个过程起一个别名。
对于方法引用类型一共有以下四种形式:
(1)引用静态方法:类名称::static方法名称;
(2)引用某个对象的方法:实例化对象::普通方法;
(3)引用某个特定类的方法:类名称::普通方法;
(4)引用构造方法:类名称::new;
package com.wschase.yinyong;
/**方法引用:
* y=f(g(z(args)))
* ()->参数
* f->{}即是执行语句
* y就相当于式return语句
* Author:WSChase
* Created:2018/12/3
*/
//注意:我们的方法引用是函数与对象接轨,但是又有个要求就是我们在使用方法引用的时候要求我们这个函数在面向对象中
//已经存在了,这个时候我们采用方法引用可以减少方法体的内容,这样的话就将函数与对象结合起来了。
//那么如果这个函数在我们面向对象里面没有,我们就需要采用Lambda表达式或者是匿名对象的方法去实现这个功能。
//方法引用的目的:覆用我们面向对象中已经实现的内容。
// //1.引用静态方法
// //String类的valueOf()方法:将基本数据类型转化为整型
// @FunctionalInterface
// interface IUtil<P,R>{
// public R switchPara(P p);
// }
//
//public class Testyinyong {
// public static void main(String[] args) {
//这个地方相当于是将接口中的方法进行了重写的,只是实现的方法是方法引用。-》前提是这个方法在面向对象中已经存在的方法。
// IUtil<Integer,String> iu=String :: valueOf;//方法引用:就是将调用静态方法这个过程起了个别名叫iu,并且限定了这个别名的类型
// String str=iu.switchPara(1000);//相当于调用了String.valueOf(1000)
// System.out.println(str.length());
// }
//}
////2.引用对象方法
//@FunctionalInterface
//interface IUtil<R>{
// public R switchPara();
//}
//public class TestDemo{
// public static void main(String[] args) {
// IUtil<String> iu="hello"::toUpperCase;//进行方法引用
// System.out.println(iu.switchPara());
// }
//}
////3.引用类中普通方法
////String有一个compareTo方法,次方法为普通方法
//@FunctionalInterface
//interface IUtil<R,P>{
// public R compare(P p1,P p2);
//}
//public class Testyinyong{
// public static void main(String[] args) {
// IUtil<Integer,String> iu=String::compareTo;
// System.out.println(iu.compare("刘","霍"));
// }
//}
////4.引用构造方法
//class Person{
// private String name;
// private int age;
// public Person(String name,int age){
// super();
// this.name=name;
// this.age=age;
// }
//
// @Override
// public String toString() {
// return "Person [name="+name+"age="+age+"]";
// }
//}
//@FunctionalInterface
//interface IUtil<R,PN,PA>{//这个括号里面的内容是方法返回类型和参数类型
// public R createPerson(PN p1,PA p2);
//}
//public class Testyinyong{
// public static void main(String[] args) {
// IUtil<Person,String,Integer> iu=Person::new;
// System.out.println(iu.createPerson("yusima",25));
// }
//}
四、内建函数式接口
java.util.function实际上函数式编程分为以下四种接口:
1.功能型函数式接口:public interface Function<T,R>R apply(T t);
2.供给型函数式接口:public interface Supplier T get();
3.消费型函数式接口:public interface Consumer void accept(T t);
4.断言型接口:public interface Predicate boolean test(T t);
package com.wschase.neijian;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**内建函数式接口
* Author:WSChase
* Created:2018/12/3
*/
////1.功能型接口(有进有出)
//public class Neijian {
// public static void main(String[] args) {
// Function<Integer,String>fun=String::valueOf;
// System.out.println(fun.apply(1000));
// }
//}
////2.供给型(无进有出)
//public class Neijian{
// public static void main(String[] args) {
// Supplier<String> sup="hello"::toUpperCase;
// System.out.println(sup.get());
// }
//}
////3.消费型(有进无出)
//public class Neijian{
// public static void main(String[] args) {
// Consumer<String> cons=System.out::println;
// cons.accept("哈喽");
//
// }
//}
////4.断言型(预测以什么开始,以什么结束)
//public class Neijian{
// public static void main(String[] args) {
// Predicate<String> pre="##jsshhd112"::startsWith;
// System.out.println(pre.test("##"));
// }
//}