Lambda表达式——java

目录

 

一、Lambda表达式

二、函数式接口

​三、方法引用

 四、Lambda表达式应用


一、Lambda表达式

传递方法/代码块(函数式程序语言设计),java8支持此项功能,通过java的Lambda表达式实现。

  • 通常表示一个匿名函数
  • Lambda表达可以当作参数,传递给其他高级函数.

Lambda表达式定义:

  • 类似于匿名方法,一个没有名字的方法
  • 参数,箭头,1/多个表达式语句组合,参数一般需要用()括号括住
  • 可以忽略写参数的类型
  • 坚决不声明返回值类型
  • 没有public/protected/private/static/final等修饰符
  • 单句表达式,将直接作为返回值,不能用大括号括住
  • 多句,必须用大括号,带return语句,也算多句

特殊情况:

  • 无参数的时候,仅包留括号“()”,箭头表达式
  • 一个参数的时候,可以省略括号
  • 如果有返回值,返回值类型会在上下午推断出来的,无需声明
  • 如果只在某几个分治有返回值,这样会报错不合法。

Lambda表达式使用举例:

public class StringOrderTest {

	public static void main(String[] args) {
		String[] planets = new String[] { 
				"Mercury", "Venus", "Earth", "Mars", 
				"Jupiter", "Saturn", "Uranus",
				"Neptune" };	

		System.out.println(Arrays.toString(planets));
		System.out.println("=======================");
		System.out.println("使用Lambda, 长度从小到大:");
		Arrays.sort(planets, 
				(String first, String second) 
				   -> first.length() - second.length());
		System.out.println(Arrays.toString(planets));
		
		System.out.println("使用Lambda, 长度从大到小:");
		Arrays.sort(planets, (first, second) -> (-1) * (first.length() - second.length()));
		System.out.println(Arrays.toString(planets));
		
		System.out.println("使用Lambda, 长度从大到小:");
		Arrays.sort(planets, 
			(String first, String second) -> 
			{
				int result = (-1) * (first.length() - second.length());
				return result;
			}
		);
		System.out.println(Arrays.toString(planets));

	}

}
输出:
[Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune]
=======================
=======================
使用Lambda, 长度从小到大:
[Mars, Venus, Earth, Saturn, Uranus, Mercury, Jupiter, Neptune]
使用Lambda, 长度从大到小:
[Mercury, Jupiter, Neptune, Saturn, Uranus, Venus, Earth, Mars]
使用Lambda, 长度从大到小:
[Mercury, Jupiter, Neptune, Saturn, Uranus, Venus, Earth, Mars]

二、函数式接口

Lambda表达式应用过程可以通过是实现函数式接口。

函数式接口:

  • 是一个接口,符合java解耦定义
  • 只包含一个未实现抽象方法的接口
  • 可以包括其他的defult方法,static方法,private方法
  • 由于只有一个未实现的方法,所以Lambda表达式可以自动填充上这个未实现的方法
  • 采用Lambda表达式,可以自动创建一个(伪)嵌套类对象(没有及时嵌套类class文件产生),然后使用,比嵌套类更加轻量,更加简洁高效

比如上例中就相当于自动填充了Compartor接口中的compare方法。

值得注意的是,虽然Compartor接口中含有两个未实现的方法,为compare和equals方法,但是几乎任何实现Compartor接口的类,肯定继承了Object类,也就是有equals实现,所以与上述函数式接口定义不矛盾。

自定义函数式接口:

1.自定义一个接口函数,并且只含有一个未实现方法

补充:

  • 可以写自带注解:@FunctionalInterface会检查接口内是否只有一个未实现的方法。
  • jdk8引入了Lamdba表达式,接口中只有一个抽象方法时才会被填充,所以jdk8开始,接口中支持默认方法/静态方法/私有方法。
@FunctionalInterface
public interface StringChecker {
	public boolean test(String s);
	//public boolean test2(String s);
}

2.利用Lambda表达式将接口内的方法填充并使用

public class PredicateTest {

	public static void main(String[] args) {
		String[] planets = new String[] { 
				"Mercury", "Venus", "Earth", "Mars", 
				"Jupiter", "Saturn", "Uranus", "Neptune" };
		
		StringChecker evenLength = s -> 
			{
				if(s.length()%2 == 0)
					return true;
				return false;
			};
			
		for(String p : planets)	{
			if(evenLength.test(p)) {
				System.out.println(p);
			}
		}
		
		
	
	}
}
输出:
Mars
Saturn
Uranus

为解决大量重复性的函数式接口,会使源代码膨胀。所以系统自带函数式接口,位于java.util.function包中

常用的几个:

 Preducate:test()方法:

示例:

import java.util.function.Predicate;

public class PredicateTest {

	public static void main(String[] args) {
		String[] planets = new String[] { 
				"Mercury", "Venus", "Earth", "Mars", 
				"Jupiter", "Saturn", "Uranus", "Neptune" };
		
		Predicate<String> oddLength = s -> 
			s.length()%2 == 0 ? false:true;
			
		for(String p : planets)	{
			if(oddLength.test(p)) {
				System.out.println(p);
			}
		}
	}
}

Consumer:accept()方法:

Function:apply()方法:(大写)

Supplier:get()方法:


三、方法引用

将方法作为变量,传递给其他方法。Lambda表达式支持传递现有的库函数,可分为以下几类,格式通常以::隔开:

1.类::静态方法,如Math.abs方法

示例:

public class ClassStaticMethodTest {
	public static double worker(NumFunction nf, double num)//2.创建接口函数
	{
		return nf.calculate(num);
	}
	public static void main(String[] args) {
		double a = -5.3;
		double b = worker(Math::abs, a);//3.引用方法
		System.out.println(b);
		
		double c = worker(Math::floor, a);//引用方法
		System.out.println(c);
	}	
}

interface NumFunction {//1.创建接口
	double calculate(double num);
}
输出:
5.3
-6.0

2.类::实例方法

 3.对象::实例方法

 支持this::实例方法和super::实例方法。

如:

 super::实例方法引用则是父类有此实例方法。

4.Class::new,调用某类构造函数,创造对象。

Supplier为get方法,返回数据工厂,没有参数。

Class[]::new,支持数组对象的引用。

回顾一下:IntFunction是接受一个参数返回一个值。

 四、Lambda表达式应用

1.变量遮蔽

import java.util.function.Consumer;

public class LambdaScopeTest {
	public int x = 0;//3

	class FirstLevel {

		public int x = 1;//2

		void methodInFirstLevel(int x) {//1,来自5处
	            
			// The following statement causes the compiler to generate
			// the error "local variables referenced from a lambda expression
			// must be final or effectively final" in statement A:
			//
			// x = 99;
			Consumer<Integer> myConsumer = (y) -> //6来自4处
				{
					System.out.println("x = " + x); // Statement A,来自1处
	                System.out.println("y = " + y);//7来自6处
	                System.out.println("this.x = " + this.x);//来自2处
	                System.out.println("LambdaScopeTest.this.x = " +//来自3处
	                    LambdaScopeTest.this.x);
	            };

	        myConsumer.accept(x);//4,来自1处
		}
	}

	public static void main(String... args) {
		LambdaScopeTest st = new LambdaScopeTest();
		LambdaScopeTest.FirstLevel fl = st.new FirstLevel();
		fl.methodInFirstLevel(23);//5
	}
}
输出:
x = 23
y = 23
this.x = 1
LambdaScopeTest.this.x = 0

2.Lambda的this指代

this只得是创建这个表达式得方法得this参数


public class ThisScopeTest {	
	private String name = "def";

	public static void main(String[] args) {
		new ThisScopeTest().test();
	}
	
	public void test() {
		StringOperation obj = ()->
		{
			System.out.println(this.name);
			System.out.println(getName());
		};
		obj.operate();
	}
	public String getName() {
		return this.name;
	}	
}

interface StringOperation {
	String name = "abc";
	public void operate();
}
输出:
def
def

3.比较

lambda表达式与嵌套类比较

  • 优先级比嵌套类高
  • 短小精悍,本身可以自描述
  • 无法创建命名实例,因为变量遮蔽,无法获取自身得引用(this)

方法引用与自定义Lambda表达式比较

  • 方法引用优先级更高
  • 系统自带得方法引用更加简洁高效
  • 对于复杂得Lambda表达式,采用方法引用更加清晰,且更加容易维护

尽可能地使用标准函数式接口,就时java自带地常用地四个接口,让代码更简洁,更容易学习

使用Lambda表达式地使用场景:刚好只要需要实现接口中一个抽象方法的实例,这时候用Lambda表达式就行了。

参考中国大学mooc《java核心技术》

发布了55 篇原创文章 · 获赞 17 · 访问量 4988

猜你喜欢

转载自blog.csdn.net/weixin_43698704/article/details/104237500