【函数式接口、方法引用】
01.第一章:函数式接口_概念及格式:
1).概念:有且只有一个抽象方法的接口。(可以同时有默认方法、静态方法...)
2).格式:
修饰符(public,默认) interface 接口名{
public abstract void show();
//可以同时有其它:默认方法、静态方法.....但不能再有抽象方法了
}
02.第一章:函数式接口aaa@qq.com注解:
1).为了让其它同事,项目组其它成员可以使用我们的类时,使用Lambda表达式,通常我们会主动的去设计并定义一些“函数式接口”,并且定义一些方法来使用这些接口作为参数,这样,当同事调用我们的方法时,就可以很方便的使用Lambda表达式。
2).定义“函数式接口”很简单--有且只有一个抽象方法即可。
3).JDK8同时为我们提供了一种“注解”aaa@qq.com。它就类似于:
@Override注解--强制重写父类方法。
@FunctionalInterface注解强制修饰的接口为:函数式接口,否则编译错误;
4).示例代码:
@FunctionalInterface//告诉编译器:下面的接口是函数式接口
interface IA{
public void show();
default void show1(){
}
}
03.第一章:函数式接口练习自定义函数式接口(无参无返回值):
interface IA{
public void show();
}
class Zi implements IA{
public void show(){
System.out.println("子类--show()....");
}
}
public class Demo {
public static void main(String[] args) {
//1.方式一:子类对象
fun(new Zi());
//2.方式二:匿名内部类
fun(new IA(){
public void show(){
System.out.println("匿名内部子类--show()....");
}
});
//3.方式三:Lambda表达式--
fun(()->{//使用"无名的方法"代替了子类的show()
System.out.println("Lambda表达式--show()");
});
}
private static void fun(IA a) {
a.show2();//new Zi().show()//匿名子类.show()
}
}
04.第一章:函数式接口练习自定义函数式接口(有参有返回值):
interface IA{
public int calc(int a, int b);
}
class Zi implements IA{
@Override
public int calc(int a, int b) {
return a + b;
}
}
public class Demo {
public static void main(String[] args) {
//1.传递子类对象
print(new Zi());//执行Zi中的加法
//2.传递匿名内部子类对象
print(new IA(){
@Override
public int calc(int a, int b) {
return a * b;
}
});//执行匿名子类中的"乘法"
//3.传递Labmda
print((int x,int y)->{return x - y;});//执行Lambda中的"减法"
}
public static void print(IA ia) {
int result = ia.calc(10, 20);
System.out.println(result);
}
}
05.第二章:函数式编程Lambda的应用延迟执行:
1).未延迟:效率低:
public static void main(String[] args) {
String msg1 = "日期:2018-08-27";
String msg2 = "异常:NullPointerException";
String msg3 = "位置:Demo.java 13行";
printLog(2, msg1 + msg2 + msg3);
}
public static void printLog(int level, String msg) {
if (level == 1) {
System.out.println("写入日志:");
System.out.println(msg);
}else{
System.out.println("不写日志:");
System.out.println(msg);
}
}
2).延迟:效率高:
interface MessageBuilder{
public String buildMsg();
}
public class Demo {
public static void main(String[] args) {
String msg1 = "日期:2018-08-27";
String msg2 = "异常:NullPointerException";
String msg3 = "位置:Demo.java 13行";
//使用匿名内部子类对象
printLog(2, new MessageBuilder() {
@Override
public String buildMsg() {
System.out.println("开始拼接信息....");
return msg1 + msg2 + msg3;
}
});
//使用Lambda代替
printLog(1,()-> msg1 + msg2 + msg3);
}
public static void printLog(int level, MessageBuilder mb) {
if (level == 1) {
System.out.println("写入日志:");
System.out.println(mb.buildMsg());//调用方法,拼接字符串
}else{
System.out.println("不写日志:");
//不调方法,不拼接字符串
}
}
}
06.第二章:函数式编程Lambda的应用方法形参是自定义接口使用Lambda作为形参和返回值:
1).Lambda作为“形参”:当我们调用方法,发现方法定义了一个“接口”类型的形参,而且接口是一个“函数式接口--有且仅有一个抽象方法”,这时就可以传递一个Lambda:
interface IA{
public void show();
}
public class Demo{
public static void main(String[] args){
fun(()->{for(int i = 0;i < 10 ; i++){
System.out.println("Hello");
}});
}
public static void fun(IA a){
a.show();
}
}
2).Lambda作为“返回值”:当我们“编写方法”时,可以定义返回值类型是一个“函数式接口类型”,如果是这样,可以返回一个Lambda表达式:
interface IA{
public void show();
}
public class Demo{
public static void main(String[] args){
IA a = getIa();
a.show();
}
public static IA getIa(){
return ()->System.out.println("呵呵...");
}
}
07.第二章:函数式编程练习方法形参是类库接口使用Lambda作为参数和返回值:
public class Demo{
public static void main(String[] args){
Runnable run = get();
new Thread(run).start();
//Lambda作为形参
set(()->System.out.println("作为参数的Lambda线程启动..."));
}
//使用Lambda做返回值
public static Runnabel get(){
return ()->System.out.println("Lambda线程启动...");
}
public static void set(Runnable run){
new Thread(run).start();
}
}
08.第三章:方法引用_使用自定义静态方法替代Lambda:
interface IA{
public void show();
}
public class Demo {
public static void main(String[] args) {
// fun1(() -> System.out.println("呵呵"));
fun1(Demo::method);//使用Demo类的method()方法代替:子类的show()、代替Lambda表达式
}
private static void fun1(IA a) {
a.show();
}
public static void method() {
System.out.println("呵呵");
}
}
09.第三章:方法引用_使用类库静态方法替代Lambda:
@FunctionalInterface
interface IA{
public int calc(int a, int b);
}
public class Demo {
public static void main(String[] args) {
//1.使用Lambda做加法
fun((x,y)-> x + y,10,20);
//2.使用Lambda求最大值
// fun((x, y) -> x > y ? x : y);
//3.使用Math类的max(int a,int b) 方法代替
fun(Math::max,10,20);
}
public static void fun(IA ia,int t ,int k) {
int n = ia.calc(t, k);
System.out.println("n = " + n);
}
}
10.第三章:方法引用_替代原则:
1).现有方法的“形参”和“返回值”要跟被替代的“抽象方法”的形参和返回值要一致。
11.第三章:方法引用_使用对象成员方法引用替代Lambda:
@FunctionalInterface
interface IGame{
public void run();
}
class Student{
public void playGame(IGame game) {
game.run();
}
}
class Teacher{
public void reading(){
System.out.println("老师喜欢读书....");
}
}
public class Demo {
public static void main(String[] args) {
Student stu = new Student();
// stu.playGame(()-> System.out.println("Lambda玩儿:王者荣耀"));
Teacher t = new Teacher();
stu.playGame(t::reading);
stu.playGame(new Teacher()::reading);
}
}
12.第三章:方法引用_使用super父类方法替代Lambda:
@FunctionalInterface
interface IGame{
public void run();
}
class Fu{
public void like(){
System.out.println("父亲喜欢喝酒...");
}
}
class Student extends Fu{
public void playGame(IGame game) {
game.run();
}
public void like(){
//super引用父类
/*playGame(new IGame() {
@Override
public void run() {
System.out.println("我喜欢喝啤酒....");
}
});
playGame(()-> System.out.println("我喜欢喝啤酒...."));
playGame(()-> super.like());*/
playGame(super::like);//这是"代替(引用),不是"调用"
}
}
public class Demo {
public static void main(String[] args) {
Student stu = new Student();
//super引用测试
stu.like();
}
}
13.第三章:方法引用_使用this本类方法替代Lambda:
@FunctionalInterface
interface IGame{
public void run();
}
class Student{
public void playGame(IGame game) {
game.run();
}
public void like(){
//预期打印:我喜欢羽毛球....
playGame(()-> System.out.println("我喜欢羽毛球..."));
playGame(()->this.show());
playGame(this::show);
}
public void running(){
System.out.println("我喜欢跑步...");
}
public void show(){
System.out.println("我喜欢羽毛球...");
}
}
public class Demo {
public static void main(String[] args) {
Student stu = new Student();
stu.like();
}
}
14.第三章:方法引用_类的构造器引用:
class Cat{
public void show(){
System.out.println("小猫喵喵....");
}
}
interface CatFactory{
public Cat getCat();
}
public class Demo {
public static void main(String[] args) {
myGetCat(new CatFactory() {
@Override
public Cat getCat() {
return new Cat();
}
});
myGetCat(()->new Cat());
//使用构造引用
myGetCat(Cat::new);
}
private static void myGetCat(CatFactory cf) {
Cat c = cf.getCat();
c.show();
}
}
15.第三章:方法引用_数组构造器引用:
interface IA{
public int[] makeArray(int length);
}
public class Demo {
public static void main(String[] args) {
//1.Lambda
fun((int len)->{ return new int[len]; },5);
//2.数组构造引用
fun(int[]::new, 10);
}
private static void fun(IA a, int len) {
int[] arr = a.makeArray(len);
System.out.println("新数组的长度:" + arr.length);
}
}
16.第四章:常用函数式接口_生产接口_Supplier接口:
public class Demo {
public static void main(String[] args) {
setSpl(()->{return "Hello";});
setSplInteger(()-> {return 10;});
}
public static void setSpl(Supplier<String> spl) {
System.out.println(spl.get());
}
public static void setSplInteger(Supplier<Integer> intSpl) {
System.out.println("一个int值:" + intSpl.get());
}
}
17.第四章:常用函数式接口消费接口_Consumer接口抽象方法accept:
public class Demo {
public static void main(String[] args) {
f1((s)-> System.out.println(s),"Hello");
f2((n)-> System.out.println(n),10);
}
public static void f1(Consumer<String> c,String str){
c.accept(str);
}
public static void f2(Consumer<Integer> c, Integer integer) {
c.accept(integer);
}
}
18.第四章:常用函数式接口Consumer接口默认方法andThen:
public class Demo {
private static void consumeString(Consumer<String> one,
Consumer<String> two) {
// one. andThen(two). accept("Hello") ;
new Consumer<String>(){
@Override
public void accept(String s) {
one.accept(s);
two.accept(s);
}
}.accept("Hello");
}
public static void main(String[ ] args) {
consumeString(
s -> System. out. println(s. toUpperCase()),
s -> System. out. println(s. toLowerCase())
);
}
}
学习目标总结:
01.能够使用@FunctionalInterface注解
1).必须在”函数式接口”上使用,强制编译器按照函数式接口的语法检查此接口。
2).示例:
@FunctionalInterface
interface IA{
public void show();
}
02.能够自定义无参无返回函数式接口
@FunctionalInterface
interface IA{
public void show();
}
03.能够自定义有参有返回函数式接口
@FunctionalInterface
interface IA{
public int calc(int a,int b);
}
public class Demo{
public static void main(String[] args){
f1((x,y)->x + y,10,20);
}
public static void f1(IA a,int x,int y){
System.out.println(a.calc(x,y));
}
}
04.能够理解Lambda延迟执行的特点
interface MessageBuilder{
public String buildMsg();
}
public class Demo {
public static void main(String[] args) {
String msg1 = “日期:2018-08-27”;
String msg2 = “异常:NullPointerException”;
String msg3 = “位置:Demo.java 13行”;
//使用匿名内部子类对象
printLog(2, new MessageBuilder() {
@Override
public String buildMsg() {
System.out.println(“开始拼接信息….”);
return msg1 + msg2 + msg3;
}
});
//使用Lambda代替
printLog(1,()-> msg1 + msg2 + msg3);
}
public static void printLog(int level, MessageBuilder mb) {
if (level == 1) {
System.out.println("写入日志:");
System.out.println(mb.buildMsg());//调用方法,拼接字符串
}else{
System.out.println("不写日志:");
//不调方法,不拼接字符串
}
}
}
05.能够使用Lambda作为方法的参数
interface IA{
public void show();
}
public static void main(String[] args){
f1(()->System.out.println(“Hello”));
}
public static void f1(IA a){
a.show();
}
06.能够使用Lambda作为方法的返回值
public static void main(String[] args){
Runnable run = f1();
new Thread(run).start();
}
public static Runnable f1(){
return ()->System.out.println(“Lambda线程开始运行…”);
}
07.能够使用输出语句的方法引用
interface IA{
public void show(String s);
}
public static void main(String[] args){
//1.目标:打印:HelloWorld:使用Lambda的形式
f1((String s)-> System.out.println(s),”HelloWorld”);
// 由于:show(String s)方法就是:接收一个String 并打印。
// 类库中有个方法:System.out.println()可以做一样的操作
//2.使用System.out.println(String s)方法替换show(String s)
f1(System.out::println,”HelloWorld”);
}
public static void f1(IA a,String s){
a.show(s);
}
08.能够通过4种方式使用方法引用
1).静态方法引用
(类名::方法名)
2).类成员方法引用:
(new 对象()::方法名)
3).super和this引用:
4). 构造器引用:
1).类构造器:Cat::new
2).数组构造器;int[]::new
09.能够使用类和数组的构造器引用
10.能够使用Supplier函数式接口:生产者接口
public class Demo {
public static void main(String[] args) {
setSpl(()->{return “Hello”;});
setSplInteger(()-> {return 10;});
}
public static void setSpl(Supplier<String> spl) {
System.out.println(spl.get());
}
public static void setSplInteger(Supplier<Integer> intSpl) {
System.out.println("一个int值:" + intSpl.get());
}
}
11.能够使用Consumer函数式接口
public class Demo {
public static void main(String[] args) {
f1((s)-> System.out.println(s),”Hello”);
f2((n)-> System.out.println(n),10);
}
public static void f1(Consumer<String> c,String str){
c.accept(str);
}
public static void f2(Consumer<Integer> c, Integer integer) {
c.accept(integer);
}
}