Java-进阶-day13-函数式编程

Java-进阶-day13-函数式编程

今日内容
  • Lambda
  • 接口中新特性
  • 方法引用

一.Lambda

体验Lambda的更优写法

  • 理解
  • 简单 看不懂

    • 面向过程: 强调的是过程,做一个事情的每一步该怎么做
    • 面向对象: 强调的是对象,找对象帮我们做事情
    • 函数式思想: 强调的是目的是什么 ,而不关注要怎么做

Lambda标准格式介绍

  • 格式:
  • (形式参数) -> {方法体}
  • 三个部分
    • (形式参数): 看作是一个普通方法需要传递的参数的地方
    • -> : jdk8 出现的新语法 代表的是一个指向的动作
    • {} : 方法体,需要执行的代码,看作是一个普通方法的方法体
  • 格式说明:
  • Lambda的本质是什么?

    匿名方法,就是没有名字的方法
  • Lambda主要解决的问题是什么?

    简化匿名内部类写法的

定义方法的格式:

  1. 无参无返回值
  2. 有参无返回值
  3. 带参带返回值

Lambda表达式练习

  • 练习一(无参无返回值抽象方法的练习)
  • 案例步骤
    • 定义一个接口(Eatable),里面定义一个抽象方法:void eat();
    • 定义一个测试类(EatableDemo),在测试类中提供两个方法
      • 一个方法是:useEatable(Eatable e)
      • 一个方法是主方法,在主方法中调用useEatable方法有参无返回值抽象方法的练习
		/*
		    Lambda表达式的格式:(形式参数) -> {代码块}

		    练习1:
		        1:定义一个接口(Eatable),里面定义一个抽象方法:void eat();
		        2:定义一个测试类(EatableDemo),在测试类中提供两个方法
		            一个方法是:useEatable(Eatable e)
		            一个方法是主方法,在主方法中调用useEatable方法
		 */
				public class EatableDemo {
				    public static void main(String[] args) {
				        //在主方法中调用useEatable方法
				        Eatable e = new EatableImpl();
				        useEatable(e);

				        //匿名内部类
				        useEatable(new Eatable() {
				            @Override
				            public void eat() {
				                System.out.println("一天一苹果,医生远离我");
				            }
				        });

				        //Lambda表达式
				        useEatable(() -> {
				            System.out.println("一天一苹果,医生远离我");
				        });
				    }

				    /*
				       接口作为方法的参数:
				            传递的是该接口的实现类的对象
				            1. 传统方式 -- 定义一个类,实现该接口
				            2. 匿名内部类,简化第一种方式
				            3. 使用Lambda表达式 ,简化第二种方式
				     */
				    private static void useEatable(Eatable e) {
				        e.eat();
				    }
				}
				/*

				    接口中只有一个抽象方法,该接口称之为函数式接口
				 */
				public interface Eatable {
				    void eat();
				}

  • 练习二(有参无返回值抽象方法的练习)
  • 案例步骤
    • 定义一个接口(Flyable),里面定义一个抽象方法:void fly(String s);
    • 定义一个测试类(FlyableDemo),在测试类中提供两个方法
      • 一个方法是:useFlyable(Flyable f)
      • 一个方法是主方法,在主方法中调用useFlyable方法
		/*
		    Lambda表达式的格式:(形式参数) -> {代码块}

		    练习2:
		        1:定义一个接口(Flyable),里面定义一个抽象方法:void fly(String s);
		        2:定义一个测试类(FlyableDemo),在测试类中提供两个方法
		            一个方法是:useFlyable(Flyable f)
		            一个方法是主方法,在主方法中调用useFlyable方法
		 */
		public class FlyableDemo {
		    public static void main(String[] args) {
		        //在主方法中调用useFlyable方法
		        //匿名内部类
		        useFlyable(new Flyable() {
		            @Override
		            public void fly(String s) {
		                System.out.println(s);
		                System.out.println("飞机自驾游");
		            }
		        });
		        System.out.println("--------");

		        //Lambda
		        useFlyable((String s) -> {
		            System.out.println(s);
		        });

		    }

		    private static void useFlyable(/*String s,*/ Flyable f) {
		        f.fly("风和日丽,晴空万里");
		    }
		}


		public interface Flyable {
		    void fly(String s);
		}

  • 练习三(有参有返回值抽象方法的练习)
  • 案例步骤
    • 定义一个接口(Addable),里面定义一个抽象方法:int add(int x,int y);
    • 定义一个测试类(AddableDemo),在测试类中提供两个方法
      • 一个方法是:useAddable(Addable a)
      • 一个方法是主方法,在主方法中调用useAddable方法
/*
    Lambda表达式的格式:(形式参数) -> {代码块}

    练习3:
        1:定义一个接口(Addable),里面定义一个抽象方法:int add(int x,int y);
        2:定义一个测试类(AddableDemo),在测试类中提供两个方法
            一个方法是:useAddable(Addable a)
            一个方法是主方法,在主方法中调用useAddable方法
 */
	public class AddableDemo {
	    public static void main(String[] args) {
	        //在主方法中调用useAddable方法
	        useAddable((int x,int y) -> {
	            return x + y;
	//            return  x - y;
	        });
	    }

	    private static void useAddable(Addable a) {
	        int sum = a.add(10, 20);
	        System.out.println(sum);
	    }
	}


		public interface Addable {
		    int add(int x, int y);
		}

Lambda注意事项

  • Lambda表达式的省略模式
  • 总结:
    • 省略的思路:

      • 可推导 可省略
    • 省略的规则:

      • () : 参数的类型可以省略(参数的类型要省都省) ; 如果参数有且仅有一个,那么小括号可以省略
      • {} : 如果代码块的语句只有一条,可以省略大括号和分号,如果有return,return也要省略掉
  • Lambda表达式的注意事项

必须是一个接口 ,接口中有且仅有一个抽象方法必须有上下文,否则推断不出来的

  • 常用的方式,是在于方法参数传递
  • 将Lambda的表达式可以赋值给一个接口
  • Lambda表达式和匿名内部类的区别
  • 所需类型不同
    • 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
    • Lambda表达式:只能是接口
  • 使用限制不同
    • 如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
    • 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
  • 实现原理不同
    • 匿名内部类:编译之后,产生一个单独的.class字节码文件
    • Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成

二.接口新特性

  • 接口中可以定义的内容有?
  • 总结:
    • 接口中:
    • JDK7:
      • 常量
      • 抽象方法
    • JDK8:
      • 默认方法(default)
      • 静态方法(static)
    • JDK9:
      • 私有方法(private)
        • 普通私有方法
        • 静态私有方法
  • 接口中默认方法
  • 总结:

  • 格式:

    • public default 返回值 方法名称(参数类表){}
  • 加入默认方法, 可以解决什么样的问题?

    • 解决接口升级的问题
  • 接口中静态方法
  • 总结:
    • 格式:

      • public static 返回值类型 方法名(参数类别){}

      • 注意事项:

        • 接口中有静态方法,只能使用接口名调用静态方法,不允许使用实现类的对象或者实现类的类名调用
      • 使用的格式:

        • 接口名.静态方法(参数列表);
  • 接口中私有方法
  • 总结:
    • 普通私有方法:

      • private 返回值类型 方法名(参数类别){}
    • 静态私有方法:

      • private static 返回值类型 方法名(参数类别){}
    • 注意事项:

      • 静态方法只能访问静态私有的方法
      • 普通的方法能访问静态私有的也能访问非静态私有的方法
    • 接口中私有方法的作用:

      • 用于抽取默认方法和静态方法的重复性的代码

三.方法引用

  • 体验方法引用
  • 总结:
    • 方法的引用用于优化Lambda的
  • 方法引用语法
  • 方法引用的符号: ::
  • 引用类方法
  • 总结:

    • 格式:
      • 类名::静态方法
  • 案例代码:

		/*
		    练习:
		        1:定义一个接口(Converter),里面定义一个抽象方法:
		            int convert(String s);
		        2:定义一个测试类(ConverterDemo),在测试类中提供两个方法
		            一个方法是:useConverter(Converter c)
		            一个方法是主方法,在主方法中调用useConverter方法
		 */
		public class ConverterDemo {
		    public static void main(String[] args) {
		        //在主方法中调用useConverter方法
		        // 使用匿名内部类
		        useConverter(new Converter() {
		            @Override
		            public int convert(String s) {
		                return Integer.parseInt(s);
		            }
		        });

		//        useConverter((String s) -> {
		//            return Integer.parseInt(s);
		//        });

		        useConverter(s -> Integer.parseInt(s));

		        //引用类方法
		        useConverter(Integer::parseInt);

		        //Lambda表达式被类方法替代的时候,它的形式参数全部传递给静态方法作为参数
		    }

		    private static void useConverter(Converter c) {
		        int number = c.convert("666");
		        System.out.println(number);
		    }
		}


		public interface Converter {
		    // 将字符串转换为整数int
		    int convert(String s);
		}

  • 引用对象的实例方法
  • 总结:

    • 格式:
      • 对象::成员方法
  • 案例代码:

public class PrinterDemo {
    public static void main(String[] args) {
        //在主方法中调用usePrinter方法

//        usePrinter((String s) -> {
////            String result = s.toUpperCase();
////            System.out.println(result);
//            System.out.println(s.toUpperCase());
//        });

        usePrinter(s -> System.out.println(s.toLowerCase()));

        //引用对象的实例方法
        PrintString ps = new PrintString();
        usePrinter(ps::printUpper);

        //Lambda表达式被对象的实例方法替代的时候,它的形式参数全部传递给该方法作为参数
    }

    private static void usePrinter(Printer p) {
        p.printUpperCase("HelloWorld");
    }
}

public class PrintString {
    //把字符串参数变成大写的数据,然后在控制台输出
    public void printUpper(String s) {
        String result = s.toUpperCase();
        System.out.println(result);
    }
}

public interface Printer {
    void printUpperCase(String s);
}

  • 引用类的实例方法
  • 总结:
    • 格式:
      • 类名::成员方法
  • 案例代码:
public class MyStringDemo {
	    public static void main(String[] args) {
	        //在主方法中调用useMyString方法

	//        useMyString((String s,int x,int y) -> {
	//            return s.substring(x,y);
	//        });

	        useMyString((s,x,y) -> s.substring(x,y));

	        //引用类的实例方法
	        useMyString(String::substring);

	        //Lambda表达式被类的实例方法替代的时候
	        //第一个参数作为调用者
	        //后面的参数全部传递给该方法作为参数
	    }

	    private static void useMyString(MyString my) {
	        String s = my.mySubString("HelloWorld", 2, 5);
	        System.out.println(s);
	    }
	}

public interface MyString {
    String mySubString(String s, int x, int y);
}
  • 引用构造器
  • 总结:
    • 格式:
      • 类名::new
  • 案例代码:
		public class StudentDemo {
		    public static void main(String[] args) {
		        //在主方法中调用useStudentBuilder方法

		//        useStudentBuilder((String name,int age) -> {
		////            Student s = new Student(name,age);
		////            return s;
		//            return new Student(name,age);
		//        });

		        useStudentBuilder((name,age) -> new Student(name,age));

		        //引用构造器
		        useStudentBuilder(Student::new);

		        //Lambda表达式被构造器替代的时候,它的形式参数全部传递给构造器作为参数
		    }

		    private static void useStudentBuilder(StudentBuilder sb) {
		        Student s = sb.build("林青霞", 30);
		        System.out.println(s.getName() + "," + s.getAge());
		    }
		}

		public class Student {
		    private String name;
		    private int age;
		}

		public interface StudentBuilder {
		    Student build(String name, int age);
		}

		        //引用构造器
		        useStudentBuilder(Student::new);

		        //Lambda表达式被构造器替代的时候,它的形式参数全部传递给构造器作为参数
		    }

		    private static void useStudentBuilder(StudentBuilder sb) {
		        Student s = sb.build("林青霞", 30);
		        System.out.println(s.getName() + "," + s.getAge());
		    }
		}

		public class Student {
		    private String name;
		    private int age;
		}

		public interface StudentBuilder {
		    Student build(String name, int age);
		}

你可能感兴趣的:(Java进阶)