参考《Java疯狂讲义》
Lambda表达式支持将代码块作为方法参数,Lambda表达式允许使用更简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数式接口)的实例

1. Lambda表达式入门

下面先使用匿名内部类来改写(6.6介绍的命令模式Command表达式的例子)

public class CommandTest
{
public static void main(String[] args)
{
ProcessArray pa = new ProcessArray();
int[] array = {3, -4, 6, 4};
// 处理数组,具体处理行为取决于匿名内部类
pa.process(array , new Command()
{
public void process(int[] target)
{
int sum = 0;
for (int tmp : target )
{
sum += tmp;
}
System.out.println("数组元素的总和是:" + sum);
}
});
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
程序通过匿名内部类实例来封装处理行为。而Lambda表达式完全可以简化创建匿名内部类对象。

public class CommandTest2
{
public static void main(String[] args)
{
ProcessArray pa = new ProcessArray();
int[] array = {3, -4, 6, 4};
// 处理数组,具体处理行为取决于匿名内部类
pa.process(array , (int[] target)->{
int sum = 0;
for (int tmp : target )
{
sum += tmp;
}
System.out.println("数组元素的总和是:" + sum);
});
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
通过上面的对比可知;Lambda表达式主要就是代替匿名内部类的繁琐语法。不需要new Xxx(){}的语法,不需要指出重写方法的名字,也不需要给出重写方法的返回值类型——只需要给出重写方法的形参列表即可。
当使用Lambda表达式代替匿名内部类创建对象时,Lambda表达式的代码块将会替代实现抽象方法的方法体,Lambda表达式就相当于一个匿名方法。
他由三部分组成;

形参列表。形参列表允许省略形参类型。如果形参列表中只有一个参数,甚至连形参列表的括号都能省略。
箭头。英文划线和大于号组成。
代码块。如果代码块只有一条语句,Lambda表达式允许省略代码块的花括号,那么这条语句就不要用花括号表示语句的结束。Lambda代码块只有一条return语句,甚至可以省略return关键字。Lambda表达式需要返回值,而他的代码块中仅有一条省略了return的语句,Lambda表达式会自动返回该语句的值。
下面示范Lambda表达式的几种简单写法;

interface Eatable
{
void taste();
}
interface Flyable
{
void fly(String weather);
}
interface Addable
{
int add(int a , int b);
}
public class LambdaQs
{
// 调用该方法需要Eatable对象
public void eat(Eatable e)
{
System.out.println(e);
e.taste();
}
// 调用该方法需要Flyable对象
public void drive(Flyable f)
{
System.out.println("我正在驾驶" + f);
f.fly("【碧空如洗的晴日】");
}
// 调用该方法需要Addable对象
public void test(Addable add)
{
System.out.println("5与3的和为" + add.add(5, 3));
}
public static void main(String[] args)
{
LambdaQs lq = new LambdaQs();
// Lambda表达式的代码块只有一条语句,可以省略花括号
lq.eat(()-> System.out.println("苹果的味道不错"));
// Lambda表达式的形参列表只有一个形参,可以省略圆括号
lq.drive(weather ->
{
System.out.println("今天天气是" + weather);
System.out.println("ֱ直升机飞行平稳");
});
//Lambda表达式的代码块只有一条语句,可以省略花括号
// 代码块只有一条语句,即使该表达式需要返回值,也可以省略return关键字
lq.test((a , b)->a + b);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2. Lambda表达式与函数式接口
Lambda表达式的类型,也被称为“目标类型(target type)”,Lambda表达式的目标类型必须是“函数式接口(functional interface)”。函数式接口代表只包含一个抽象方法的接口。函数式接口可以有多个默认方法,类方法,但只能声明一个抽象方法。

Java 8 专门为函数式接口提供了@FunctionalInterface注解,该注解通常放在接口定义前面,该注解对程序功能没有任何作用,它用于告诉编译器执行更严格的检查——检查该接口必须是函数式接口,否者编译器报错。

@FunctionalInterface
interface FkTest
{
void run();
}

public class LambdaTest
{
public static void main(String[] args)
{
// Runnable接口中只包含一个无参数的方法
// Lambda表达式代表的匿名方法实现了Runnable接口中唯一的,无参数的方法
// 因此下面的Lambda表达式创建了一个Runnable对象
Runnable r = () -> {
for(int i = 0 ; i < 100 ; i ++)
{
System.out.println();
}
};
// 下面代码将出现错误:Object不是函数式接口
//Object obj = (www.michenggw.com) -> {
// for(int i = www.douniu157.com 0 ; i < 100 ; i ++)
// {
// System.out.println();
// }
//};
//对Lambda表达式进行强制类型转换,这样就可以确定该表达式的目标类型为Runnable函数式接口
Object obj1 = (Runnable)(www.dfgjpt.com) -> {
for(int i = 0 ; i < 100 ; i ++)
{
System.out.println();
}
};
//同样的Lambda表达式可以被当成不同的目标类型,唯一的要求是:
// Lambda表达式的参数列表与函数式接口中唯一抽象方法的形参列表相同ͬ
Object obj2 = (FkTest)() -> {
for(int i = 0 ; i < 100 ; i ++)
{
System.out.println();
}
};

从以上代码可以得出一些结论:
Lambda表达式实现的是匿名方法——因此它只能实现特定的函数接口中唯一的方法。这就意味着Lambda表达式有如下两个限制:(1)Lambda表达式的目标类型只能是明确的函数式接口。(2)Lambda表达式只能为函数式接口创建对象。
为了保证Lambda表达式的目标类型是一个明确的函数式接口,可以有如下三种方式:(1)将Lambda表达式赋值给函数式接口类型的变量(2)将Lambda表达式作为函数式接口类型的参数传给某个方法(3)使用函数式接口对Lambda表达式进行强制类型转换
Java 8 在java.util.function包下预定了大量函数式接口,典型有4类接口:

XxxFunction:这类接口中通常包含一个apply()抽象方法,该方法对参数进行处理(处理逻辑由Lambda表达式决定),然后返回一个新的值
XxxConsumer:这类接口中通常包含一个accept()抽象方法,该方法与上面的方法相似,只是没有返回值
XxxPredicate:这类接口中通常包含一个test()抽象方法,该方法用于对参数进行某种判断(由Lambda表达式决定),然后返回一个Boolean类型的值
XxxSupplier:这类接口中通常包含一个getAsXxx()抽象方法,该方法没有参数,会按某种逻辑算法(由Lambda表达式决定)返回一个数据
3. 方法引用与构造器引用
如果Lambda表达式的代码块只有一条代码,不仅可以省略花括号,还可以在代码块中使用方法引用和构造器引用。
方法引用和构造器引用可以让Lambda表达式的代码块更加简洁,方法引用和代码块引用都要使用两个英文冒号。

引用类方法
@FunctionalInterface
interface Converter{
Integer convert(String from);
}
/下面代码使用Lambda表达式创建Converter对象
Converter converter1 www.dasheng178.com= from -> Integer.valueOf(from);
Integer val =www.meiwanyule.cn converter1.convert("99");
System.out.println(val); // 将输出99

使用一行调用类方法进行替换

// 方法引用代替Lambda表达式:引用类方法
// 函数式接口中被实现的全部参数传给该类方法作为参数
Converter converter1 = Integer::valueOf;
1
2
3
引用特定对象的实例方法
// 下面代码使用Lambda表达式创建Converter对象
Converter converter2 = from -> "fkit.org".indexOf(from);
1
2
Integer value = converter2.convert("it");
System.out.println(value); // 输出2
1
2
// 方法引用代替Lambda表达式,引用特定对象的实例方法
// 函数式接口中被实现的全部参数传给该方法作为参数
Converter converter2 = "fkit.org"::indexOf;
1
2
3
3.引用某类对象的实例方法

@FunctionalInterface
interface MyTest
{
String test(String a , int b , int c);
}
//下面代码使用Lambda表达式创建MyTest对象
MyTest mt = (a , b , c) -> a.substring(b , c);

String str = mt.test("Java I Love you" , 2 , 9);
System.out.println(str); // 输出:va I Lo
// 方法引用代替Lambda表达式,引用某类对象的实例方法
// 函数式接口中被实现的第一个参数作为调用者
//后面的参数全部传递给该方法作为参数
MyTest mt = String::substring;
引用构造器
@FunctionalInterface
interface YourTest
{
JFrame win(String title);
}
// 下面代码使用Lambda表达式创建YourTest对象
YourTest yt = (String a) -> new JFrame(a);

JFrame jf = yt.win("我的窗口");
System.out.println(jf);

//构造器引用代替Lambda表达式
// 函数式接口中被实现的全部参数传给该构造器作为参数
YourTest yt = JFrame::new;

4. Lambda表达式与匿名内部类的联系与区别
Lambda表达式是匿名内部类的一种简化
相同点:

Lambda表达式与匿名内部类一样,都可以直接访问“effectively final”的局部变量,以及外部类的成员变量。
Lambda表达式与匿名内部类创建的对象一样,都可以直接调用从接口中继承的默认方法
不同之处:
匿名内部类可以为任何接口创建实例——不管接口包含多少个抽象方法,只要匿名内部类实现了所有抽象方法即可;但 Lambda表达式只能为函数式接口创建对象
匿名内部类可以为抽象类甚至普通类创建对象
匿名内部类实现的抽象方法的方法体允许调用接口中的默认方法;但 Lambda表达式的代码块不允许调用接口中的默认方法
5. 使用 Lambda表达式调用Arrays的类方法

public class LambdaArrays
{
public static void main(String[] args)
{
String[] arr1 = new String[]{"java" , "fkava" , "fkit", "ios" , "android"};
Arrays.parallelSort(arr1, (o1, o2) -> o1.length() - o2.length());
System.out.println(Arrays.toString(arr1));
int[] arr2 = new int[]{3, -4 , 25, 16, 30, 18};
// left代表素组中前一个索引处的元素,计算第一个元素时,left为1
// right代表素组中当前索引处的元素
Arrays.parallelPrefix(arr2, (left, right)-> left * right);
System.out.println(Arrays.toString(arr2));
long[] arr3 = new long[5];
// operand代表正在计算的元素索引
Arrays.parallelSetAll(arr3 , operand -> operand * 5);
System.out.println(Arrays.toString(arr3));
}

参考《Java疯狂讲义》的更多相关文章

  1. java8--类加载机制与反射(java疯狂讲义3复习笔记)

    本章重点介绍java.lang.reflect包下的接口和类 当程序使用某个类时,如果该类还没有被加载到内存中,那么系统会通过加载,连接,初始化三个步骤来对该类进行初始化. 类的加载时指将类的clas ...

  2. java8--NIO(java疯狂讲义3复习笔记)

    NIO采用内存映射文件的方式处理输入输出,NIO将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件了(这种方式模拟了操作系统上的虚拟内存的概念),通过这种方式来进行输入输出比传统的 ...

  3. Java学习 面向对象(下)——Java疯狂讲义th4

    面向对象(下) [TOC] 包装类 通过包装类可以把8个基本类型的值包装成对象使用. 自动拆箱.自动装箱 把字符串类型值转换成基本类型的值: 包装类的 parseXxx(String s)静态方法 包 ...

  4. 《Java疯狂讲义》(第3版)学习笔记 2 - Java语言的运行机制

    内容 1.高级语言的运行机制 2.Java 语言的运行机制 1.高级语言的运行机制 高级语言主要分为编译型语言和解释型语言两类. 编译型语言是指使用专门的编译器.针对特定平台(操作系统)将高级语言源代 ...

  5. 《Java疯狂讲义》(第3版)学习笔记 1 - 如何学习Java

    1.Java是一种面向对象语言,不要简单当做脚本使用.从基础学起,不要从Spring.J2EE.Hibernate和EJB开始学. 2.不要浮躁,应该扎扎实实先学好Java语言,然后按Java本身的学 ...

  6. java疯狂讲义--摘要

    1.一个java文件中可以有多个类,但是只能有一个public类,并且该类需要与文件同名 第6章 对象的软,弱和虚引用 1.强引用---创建一个对象,并把这个对象赋给一个引用变量.一个对象被一个以上的 ...

  7. 流程控制与数组——Java疯狂讲义

    顺序结构 if分支语句      if{} 可以有多个else if{} else{} 可以省略 switch分支语句 while循环 do while循环 for循环 嵌套循环 控制循环结构 理解数 ...

  8. java8--网络编程(java疯狂讲义3复习笔记)

    重点复习一下网络通信和代理 java的网络通信很简单,服务器端通过ServerSocket建立监听,客户端通过Socket连接到指定服务器后,通信双方就可以通过IO流进行通信. 需要重点看的工具类:I ...

  9. java8--异常处理(java疯狂讲义3复习笔记)

    try,catch,finally,throw,throws java将异常分为两种,Checked异常和Runtime异常. IndexOutOfBoundsException NumberForm ...

随机推荐

  1. mysql表的核心元数据

    索引的 mysql> show indexes from recordsInRangeTest; +--------------------+------------+------------- ...

  2. 一对多,多的逗号分隔存在新字段中(Group_concat 用法)

    sql 语句: SELECT    (        SELECT            Group_concat(t_work_group_user.user_id)        FROM     ...

  3. 「日常训练」ZgukistringZ(Codeforces Round #307 Div. 2 B)

    题意与分析(CodeForces 551B) 这他妈哪里是日常训练,这是日常弟中弟. 题意是这样的,给出一个字符串A,再给出两个字符串B,C,求A中任意量字符交换后(不限制次数)能够得到的使B,C作为 ...

  4. python爬取视频网站m3u8视频,下载.ts后缀文件,合并成整视频

    最近发现一些网站,可以解析各大视频网站的vip.仔细想了想,这也算是爬虫呀,爬的是视频数据. 首先选取一个视频网站,我选的是 影视大全 ,然后选择上映不久的电影 “一出好戏” . 分析页面 我用的是c ...

  5. APP九宫格滑动解锁的处理

    写手机自动化测试脚本关于APP九宫格滑动解锁方面采用了appium API 之 TouchAction 操作. 先是用uiautomatorviewer.bat查询APP元素坐标: 手工计算九宫格每个 ...

  6. selenium,unittest——自动化执行多个py文件脚本并生成报告

    将多个py文件的自动化脚本顺序运行,并生成报告,运行run_all_case后会自动运行文件内所有test开头的py文件并在指定文件夹report生成由脚本时间命名的报告 脚本执行后结果: 生成报告并 ...

  7. TPO-15 C1 The campus newspaper's reporter position

    TPO-15 C1 The campus newspaper's reporter position 第 1 段 1.Listen to a conversation between a Studen ...

  8. 前端开发工程师 - 01.页面制作 - 第3章.HTML

    第3章--HTML HTML简介 Hyper Text Markup Language:超文本标记语言--用于标记网页的内容 history: html(1991)雏形 -> html4.01( ...

  9. CF245H Queries for Number of Palindromes

    题目描述 给你一个字符串s由小写字母组成,有q组询问,每组询问给你两个数,l和r,问在字符串区间l到r的字串中,包含多少回文串. 时空限制 5000ms,256MB 输入格式 第1行,给出s,s的长度 ...

  10. [Clr via C#读书笔记]Cp11事件

    Cp11事件 类型之所以提供事件通知功能,是因为类型维护了一个已登记方法的列表,事件发生后,类型将通知列表登记的所有方法: 事件模型建立在委托的基础上.委托是调用回调方法的一种类型安全的方式. 设计事 ...