Java:Lambda表达式&枚举类

2019-07-04 00:00:00 java 枚举 表达式

——本文为个人学习Java记录,文章主要内容来自《疯狂java讲义》第3版

Lamdba表达式的几种简单写法:

public interface Identification {
	void identification();
}
public interface Name {
	void name(String name);
}
public interface Score {
	int score(int chineseScore, int mathematicsScore, int englishScore);
}
public class Client {
	public void getIdentification(Identification id) {
		id.identification();
	}
	public void getName(Name na) {
		na.name("小明");
	}
	public void getScore(Score sc) {
		System.out.println("我的总分是:" + sc.score(40, 50, 60));	
	}
	public static void main(String[] args) {
		Client cl = new Client();
		cl.getIdentification(()->System.out.println("我是一名学生..."));
		cl.getName(name->System.out.println("我的名字是" + name));
		cl.getScore((chineseScore, mathematicsScore, englishScore)->chineseScore + mathematicsScore + englishScore);
	}
}

输出结果:

我是一名学生...
我的名字是小明
我的总分是:150

第一种:无参数

void identification();

Lambda表达式:

()->System.out.println("我是一名学生...")

由于代码块只有一行代码,所以可以省略{ },如果含有一行以上代码则:

()->{
           System.out.println("我是一名学生...")
           ......
           ......
    }

第二种:一个参数

void name(String name);

Lambda表达式:

name->System.out.println("我的名字是" + name)

由于只有一个形参,则可以省略形参列表的( )。

第三种:多个参数

int score(int chineseScore, int mathematicsScore, int englishScore);

Lambda表达式:

(chineseScore, mathematicsScore, englishScore)->chineseScore + mathematicsScore + englishScore

score()方法需要一个返回值,所以程序将chineseScore + mathematicsScore + englishScore三科成绩的总和作为返回值,这里的return关键字可以省略。

有趣的是:getIdentification(), getName(), getScore()的形参的类型分别为Identification,Name,Score,但实际传入的是Lamdba表达式,说明此处的Lamdba表达式被当成“任意类型”来处理了。

Lamdba表达式的类型:

1. 几个简单的概念:

目标类型:Lamdba表达式的类型。

函数式接口:只包含一个抽象方法接口,其他方法可以有多个。

说明:这里的抽象方法是指接口自己特有的抽象方法,而不包含该接口从上级继承过 来的抽象方法。

2. 常见的函数式接口:Java 8中一些常用的全新的函数式接口

3. Lamdba表达式进行赋值:

  Runnerable r = ()->System.out.println("...");

这里的Runnerable是一个函数式接口,关于Lamdba表达式的两点限制:

—>Lamdba表达式的目标类型必须是明确的函数式接口。

如果不是怎么办?

a. 将Lamdba表达式赋值给函数式接口类型的变量,如上面的一行代码。

b. 将Lamdba表达式作为函数式接口类型的参数传递给方法,如文章最开始的程序。

c. 将Lamdba表达式进行强制类型转换,如下代码:

 Object obj = (Runnerable)()->System.out.println("...");

—>Lamdba表达式只能为函数接口类型创建对象。

方法引用与构造器引用:

1. 类方法引用

将数字串转换为数值

     public interface TypeConverter {
	Integer converter(String str);
     }
     public class Client {
	public static void main(String[] args) {
		TypeConverter tc = str->Integer.valueOf(str);
		int x = tc.converter("100");
		System.out.println(x);
	}
    }

使用Lamdba创建TypeConverter对象部分,原先的写法:

TypeConverter tc = str->Integer.valueOf(str);

改写之后:

TypeConverter tc = Integer::valueOf;

2. 引用特定对象的实例方法

原先的写法:

TypeConverter tc = str->"123456789".indexOf(str);

改写之后:

TypeConverter tc = "123456789"::indexOf;

3. 引用某类对象的特定方法

public interface TypeConverter {
	String converter(String str, int a, int b);
}
public class Client {
	public static void main(String[] args) {
		TypeConverter tc = (str,a,b)->str.substring(a, b);
		String x = tc.converter("Hello World", 2, 6);
		System.out.println(x);
	}
}

原先的写法:

TypeConverter tc = (str,a,b)->str.substring(a, b);

改写之后:

TypeConverter tc = String::substring;

4. 引用构造器

public class Student{
	public Student(String name) {
		System.out.println("我是一名学生,名字叫" + name);
	}
}
public interface TypeConverter {
	Student converter(String str);
}
public class Client {
	public static void main(String[] args) {
		TypeConverter tc = str->new Student(str);
		Student x = tc.converter("Hello World");
		System.out.println(x);
	}
}

原先的写法:

str->new Student(str);

改写之后:

TypeConverter tc = Student::new;

Lamdba表达式与匿名内部类的异同:

相同点:

1. Lamdba表达式和匿名内部类都可以访问局部变量,且默认用final修饰,无法重新赋值,都可以访问外部类的成员变量(包含实例变量和类变量)。

2. Lamdba表达式创建的对象和匿名内部类生成的对象,都可以调用从接口中继承的默认方法。

不同点:

1. 匿名内部类可以为任意接口创建实例,Lamdba只能为函数式接口创建实例。

2. 匿名内部类可以为抽象类、普通类创建实例,而Lamdba则不能。

3. 匿名内部类实现的抽象方法的方法体允许调用接口中的默认方法,但Lamdba表达式的代码块则不允许调用接口中的默认方法,Lamdba表达式创建的对象可以调用从接口中继承的默任方法。

使用Lamdba表达式调用Arrays中的类方法

待补充……

什么是枚举类?

  1. 枚举enum是一个关键字,与class、interface类似,所以枚举类可以看成是一种特殊的类。枚举类可以有成员变量、方法,构造器以及实现接口。枚举类的实例是有限的,可被列举的。
  2. 枚举类可以实现一个或多个接口,但是不能显示继承其他类,枚举类默认继承java.util.Enum类。
  3. 非抽象枚举类默认用final修饰,因此枚举类不能被继承。
  4. 枚举类的构造器只能使用private关键字来修饰,可以省略。
  5. 枚举类的实例,必须显示的列在程序的第一行,否则默认没有实例,且实例默认使用public static final修饰。
  6. 枚举类默认有一个values()方法,列出枚举类的所有实例,形式很像数组的foreach。
  7. 访问枚举类中的某个实例格式:EnumClass.InstanceName。

代码部分:

   public enum SeasonEnum {
	SPRING,SUMMER,AUTUMN,WINTER;
   }
   public class Client {
	public void seasonDescription(SeasonEnum sa) {
		switch(sa) {
		case SPRING:
			System.out.println("不知细叶谁裁出,二月春风似剪刀");
			break;
		case SUMMER:
			System.out.println("荷叶罗裙一色裁,芙蓉向脸两边开");
			break;
		case AUTUMN:
			System.out.println("人生若只如初见,何事秋风悲画扇");
			break;
		case WINTER:
			System.out.println("疏影横斜水清浅,暗香浮动月黄昏");
			break;
		default:
			break;
		}
	}
	public static void main(String[] args) {
		for(SeasonEnum s: SeasonEnum.values()) {
			System.out.println(s);
		}
		new Client().seasonDescription(SeasonEnum.SPRING);
	}
}

看一下遍历和访问实例部分:

for(SeasonEnum s: SeasonEnum.values()) {
			System.out.println(s);
		}
new Client().seasonDescription(SeasonEnum.SPRING);

8. 枚举类可以通过valueOf( )来获取指定枚举类的枚举值。

SeasonEnum se = Enum.valueOf(SeasonEnum.class, "SPRING");

9. 当某个枚举类的实现接口的时候,可以使用接口中的抽象方法,且每个实例可以分别实现这个方法,代码如下:

public interface Information {
	void Info();
}
public enum SeasonEnum implements Information {
	SPRING
	{
		public void Info() {
			System.out.println("不知细叶谁裁出,二月春风似剪刀");
		}
	},
	SUMMER
	{
		public void Info() {
			System.out.println("荷叶罗裙一色裁,芙蓉向脸两边开");
		}
	},
	AUTUMN
	{
		public void Info() {
			System.out.println("人生若只如初见,何事秋风悲画扇");
		}
	},
	WINTER
	{
		public void Info() {
			System.out.println("疏影横斜水清浅,暗香浮动月黄昏");
		}
	};
}
public class Client {
	public static void main(String[] args) {
		SeasonEnum se = Enum.valueOf(SeasonEnum.class, "WINTER");
		System.out.println(se);
		se.Info();
	}
}

注意格式,这里的{ }相当于类体部分,属于匿名内部子类,看源文件和class文件可以看出,Java是把它当匿名子类来处理了。

src文件:

《Java:Lambda表达式&枚举类》
《Java:Lambda表达式&枚举类》

class文件:

《Java:Lambda表达式&枚举类》
《Java:Lambda表达式&枚举类》

    原文作者:刘欢
    原文地址: https://zhuanlan.zhihu.com/p/36163515
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。

相关文章