Java基础 —— P17. Lambda & 接口组成更新 (入门) - IDEA

一、什么是Lambda?

  在Java中使用面向对象思想时强调,通过对象的思想,创建、实例化、调用对象等方式解决问题。Lambda的本质上是匿名方法,可以理解为简洁的匿名函数。Java8提供了更为简洁的语法,可以用表达式来替代函数式接口,使得代码更为简洁明了。


下面通过三种方法来对比之间的区别;
需求:创建并启动线程,在控制台输出"线程已执行;

方法① 实现Runnable接口,重写run()方法;

//定义接口实现类ThreadImp;
public class ThreadImp implements Runnable(){
		@Override
		public void run(){
			System.out.println("线程已被启动")
		}
	}
//主方法调用;
public class LambdaDemo{
	public static void main (String[] args){
		ThreadImp Thp = new ThreadImp();
		Thread t1 = new Thread(Thp);
		t1.Start();
	}	
}

方法② 匿名内部类;

public class LambdaDemo{
	public static void main (String[] args){
		new Thread(new Runnable(){
			@Override
			public void run(){
				System.out.println("匿名内部类线程已启动");
	}).start();	 
	}	
}

方法③ Lambda表达式

public class LambdaDemo{
	public static void main (String[] args){
		new Thread( ( ) -> {
		System.out.println("Lambda线程已启动")
		}).start();
	}
}


这样一对比!!Lambda表达式的代码确实简洁了许多,但是Lambda是如何使用的呢?让我们来分析一下:

<Lambda代码块分析>
  组成: (形参) -> { 代码块 }
  ( ) : 里面没有内容,可以看做是方法形式参数为空;
  -> : 箭头后面表示要做的事情;
  { } : 代码块,方法体中的内容;
组成Lambda的三要素: 形参、箭头、代码块;


演示三种情况下Lambda的使用

抽象方法无参无返回值

public class LambdaDemo{
	public static void main (String[] args){
		useEatable( ( ) -> {
			System.out.println("今天也是干饭人!")
		})}
	
	public interface Eatable{
		void eat();
  	}	

	public stitac void useEatable(Eatable e){
		e.eat();
  	}
}
控制台输出:今天也是干饭人!

抽象方法带参无返回值

public class LambdaDemo{
	public static void main (String[] args){
		useEatable( (String s) -> {
			System.out.println(s)
		})}
	
	public interface Eatable{
		void eat(String s);
  	}	

	public stitac void useEatable(Eatable e){
		e.eat("晚上要早点休息");
  	}
}
控制台输出: 晚上要早点休息

抽象方法带参有返回值

public class LambdaDemo{
	public static void main (String[] args){
		useEatable( (int x,int y) -> {
			return x+y;
		})}
	
	public interface addAble{
		int add(int x,int y);
  	}	

	public stitac void useAddable(addAble a){
		int sum = a.add(10,20);
		System.out.println(sum)
  	}
}
控制台输出:30

 看到这里相比对Lambda表达式可以是代码更简洁有了一定的概念吧,但是!Lambda表达式还有更为省略的模式;

// 正常Lambda表达式;
	useAdd((int x,int y)->{
		return x+y;
	})

// ① 省略参数(有多个参数的情况下不可只省略一个,要么全部省略,要么全部留下)
	useAdd((x,y)->{
		return x+y;
	})

// ② 只有一条一句的情况下可以把 ; 、 () 、{} 省略;
	useEat(s -> System.out.printnl(s));
	
// ③ 只有一条语句的情况下而且还有return,可以省略return;
	useAdd((x,y) -> x+y);	

现在回头想一下Lambda表达式到底有什么作用呢?

答:最直观的就是使得代码块变得非常非常简洁;

在这里插入图片描述
这两种方式的输出结果是一样的,相比于Java7的传统写法,Java8提供的Lambda的代码界面是非常干净的;

使用Lambda的时候需要记住:
1. Lambd返回的是接口的实例对象;
2. 返回值类型,参数,参数个数需要选择自己合适的函数式接口;

Lambda与匿名内部类的区别:
1. 所需要的类型不同;
   * 匿名内部类:接口、抽象类、具体类;
   * Lambda:接口;
2. 使用的限制不同;
   * 接口只有一个抽象方法时候,两者都可以使用;
   * 接口有多个抽象方法的时候,只能使用匿名内部类;
3. 实现的原理不同;
   * 匿名内部类:编译后会产生新的.class字节码文件;
   * Lambda:编译后没有产生新的字节码文件,对应的字节码在运行的时候动态生成;


二、方法引用;
序号引用方法格式
类方法类名 : : 静态方法
对象的实例化方法对象 : : 成员方法
类的实例方法类名 : : 成员方法
构造器类名 : : new

  • 引用类方法:
public class ConverterDemo {
    public static void main(String[] args) {
        //Lambda;
        useNumber(i -> Integer.parseInt(i));

        //引用类方法;类名::静态方法
        useNumber(Integer::parseInt);
    }

	public interface Number{
		int Num(String s);
	}

    private static void useNUmber(Number n){
        int number = n.Num("666");
        System.out.println(number);
    }
}
控制台输出:666

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

  • 引用对象实例化方法;
public class UpperCaseDemo {
	public static void main(String[] args){
	//Lambda;
	userPrint(s->System.out.println(s.toUpperCase()));
	
	//引用对象; 对象::成员方法
	PrintUpper Pu = new PrintUpper();
		userPrint(Pu :: printUpper);
	}

	class PrintUpepr{
		public void printUpper(String s){
			String result = s.toUpperCase();
			System.out.println(result);
		}
	}

	interface Printer{
		void PrintUpperCase(String s);
	}

	public static void usePrint(Printer p){
		p.PrintUpperCase("Roger Federer")
	}
}
控制台输出:ROGER FEDERER

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

  • 引用类的实例方法;
public class MyStringDemo {
    public static void main(String[] args) {
        //Lambda;
        useMyString((s,x,y)->s.substring(x,y));
        
        //引用类的实例方法; 类名::成员方法;
        useMyString(String::substring);
    }
	
	public interface MyString{
		String mySubString(String s , int x , int y); 
	}
	
    private static void useMyString(MyString my){
        String s = my.mySubString("Roger Federer", 0, 5);
        System.out.println(s);
    }
}
控制台输出:ROGER

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

  • 引用构造器方法;
public class Student {
    String name;
    int age;
    public Student(){ }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
	// Getter and Setter 方法省略
    }
}
public class StudentDemo {
    public static void main(String[] args) {
        //Lambda;
        useStudent((String name,int age)->{
            Student s = new Student(name,age);
            return s;
        });

        //调用构造器;类名 :: new
        useStudent(Student :: new);
    }
    
	public interface StudentBuilder{
		Student builder(String neme,int age);
	}
	
    public static void useStudent(StudentBuilder sb){
        Student s = sb.builder("Chen",18);
        System.out.println(s.getName() + "+" + s.getAge());
    }
}
控制台输出:Chen+18


三、接口组成更新;
方法格式注意事项
默认方法public default 返回值类型 方法名(参数列表) { }* 默认方法不是抽象方法。所以不强制被实现类重写;
* 如果需要重写的话需要去掉关键字default;
* public 可以省略。 default 不可省略;
静态方法public static 返回值类型 方法名(参数列表) { }* 静态方法只能通过接口名调用,不可以通过实现类名或者对象名调用;
* public 可省略 ; static不可省略 ;
私有方法private 返回值类型 方法名(参数列表){ }
pricate static 返回值类型 方法名(参数列表){ }
* 默认方法可以调用私有的静态方法和非静态方法;
* 静态方法只能调用私有的静态方法;
方法引用: : 就是引用符号* 如果使用Lambda,无需指定参数类型,无需指定重载形式,会被自动推导;
* 如果使用引用方法,也是可以根据上下文进行推导;
* 方法引用是Lambda的孪生兄弟;

  • 方法引用;
public class PrintableDemo {
    public static void main(String[] args) {
        //Lambda方法
        	usePrint( s->System.out.println(s));
        //方法引用 -> ::   原则:可推导的就是可省略的;
        	usePrint(System.out::println);

		//Lambda方法;
        	userPrintInt(p -> System.out.println(p));
        //方法引用 ::
        	userPrintInt(System.out::println);
        
    }
    
	interface Printacble{
		void printStrging(String s);
	}
    public static void usePrint(Printable p){
        p.printStrging("爱学习");
    }
	
	public interface PrintInt {
   		void printInt(int i);
	}
    public static void userPrintInt(PrintInt printInt){
        printInt.printInt(10);

    }
}

1.使用Lambda必须要有接口,并且要求接口中有且仅有一个抽象方法;
2.必须要有上下文环境,才能推导出Lambda对应的接口;
## 「局部变量的赋值」得知Lambda对应的接口: Runnable = () -> sout("Lambda表达式");
## 调用方法的参数」得知Lambda对应的接口: New Thread(()->sout("Lambda表达式")).start();

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值