0028 Java学习笔记-面向对象-Lambda表达式
匿名内部类与Lambda表达式示例
下面代码来源于:0027 Java学习笔记-面向对象-(非静态、静态、局部、匿名)内部类
package testpack;
public class Test1{
public static void main(String[] args) {
ProcessArray pa=new ProcessArray();
int[] target={5,35,-2,35,-21};
pa.process(target, new Command(){ //匿名内部类实现一个接口Command,不能传入参数
public void process(int[] target){
int sum=0;
for (int tmp:target) {
sum+=tmp;
}
System.out.println("数组元素总和: "+sum);
}
});
}
}
interface Command{
void process(int[] target);
}
class ProcessArray{
public void process(int[] target,Command cmd){
cmd.process(target);
}
}
- 下面用Lambda表达式改写
package testpack;
public class Test1{
public static void main(String[] args) {
ProcessArray pa=new ProcessArray();
int[] target={5,35,-2,35,-21};
pa.process(target, (int[] array)->{ //改写从这开始。Lambda基本结构:()->{}
int sum=0;
for (int tmp:array){
sum+=tmp;
}
System.out.println("数组元素总和: "+sum);
}); //改写结束
}
}
interface Command{
void process(int[] target);
}
class ProcessArray{
public void process(int[] target,Command cmd){
cmd.process(target);
}
}
- Lambda表达式的基本结构
- 形参列表:()圆括号部分
- 形参列表位于圆括号中
- 形参类型允许省略:上面代码中省略"int[]"也是可以的
- 如果无参数,那就只写个()
- 如果只有一个参数,可以省略圆括号
- 箭头:->
- 代码块:{}花括号部分
- 代码块部分放在花括号中
- 如果只有一条语句,那么可以省略花括号
- Lambda只有一条return语句,可以省略return关键字,只有一条语句的话,就自动返回该语句的值
- 形参列表:()圆括号部分
- Lambda表达式示例:来源于《疯狂Java讲义第三部》.《LambdaQs.java》
package testpack;
public class Test1{
public static void main(String[] args) {
LambdaQs lq=new LambdaQs();
lq.eat(()->System.out.println("苹果味道不错!")); //实际上是创建了Eatable类型的匿名对象,重写了其taste()方法
lq.drive(weather->{ //实际上是创建了Flyable类型的匿名对象,重写了其fly(String weather)方法
System.out.println("今天天气是: "+weather);
System.out.println("直升机飞行平稳!");
});
lq.test((a,b)->a+b); //创建了Addable类型的对象,重写了add(int a,int b)方法
}
}
interface Eatable{
void taste();
}
interface Flyable{
void fly(String weather);
}
interface Addable{
int add(int a,int b);
}
class LambdaQs{
public void eat(Eatable e){
System.out.println(e);
e.taste();
}
public void drive(Flyable f){
System.out.println("我正在驾驶:"+f);
f.fly("碧空如洗的晴日");
}
public void test(Addable add){
System.out.println("5+3= "+add.add(5, 3));
}
}
函数式接口与Lambda表达式
- 函数式接口:只包含一个抽象方法的接口,可以包含多个默认方法、类方法,但只能包含一个抽象方法
- 创建函数式接口的对象,可以通过匿名内部类和Lambda表达式
- 函数式接口:java.lang.Runnable、java.awt.event.ActionListener
- @FunctionalInterface 注解用于告知编译器执行更严格的检查,该接口必须是函数式接口,否则报错
- Lambda表达式的结果就是一个对象,可以将其赋值给一个函数式接口类型的变量,只要二者的参数列表匹配,示例:
package testpack;
public class Test1{
public static void main(String[] args) {
Runnable r=()->{ //Runnable是一个函数式接口,只有一个无参数的抽象方法
System.out.println("lambda表达式的实现了一个无参的方法,可以赋值给Runnable类型变量");
};
r.run();
}
}
- Lambda表达式只能为函数式接口创建对象,即只包含一个抽象方法的接口,只能实现一个方法
- Lambda表达式的目标类型必须是明确的函数式接口,但具体是哪个类型并不能确定,只要那个接口的抽象方法的参数列表跟Lambda表达式匹配即可,见示例
package testpack;
public class Test1{
public static void main(String[] args) {
Runnable r=()->System.out.println("同一个Lambda表达式可以赋值给Runnable和A,只要他们抽象方法的参数列表相匹配");
r.run();
A a=()->System.out.println("同一个Lambda表达式可以赋值给Runnable和A,只要他们抽象方法的参数列表相匹配");
a.a();
}
}
interface A{
void a();
}
- 确保正确的使用Lambda表达式
- 将其赋值给一个函数式接口类型的变量,当然参数列表得匹配
- 将其作为一个函数式接口类型的参数传给某个方法
- 使用函数式接口进行强制类型转换
- 函数式接口有很多,比如下面这些:
- java.util.function中的函数式接口
- ...Function:一般包含一个apply()方法,对参数进行处理,然后返回一个值
- ...Consumer:包含一个accept()方法,与上面方法类似,只是不返回值
- ...Predicate:包含test()方法,对参数进行判断,返回一个boolean值
- ...Supplier:包含getAs...()方法,不需要参数,返回一个数据
- ...Operator:
- java.util.Comparator
- java.util.function中的函数式接口
Lambda表达式、方法引用、构造器引用
- 如果Lambda表达式的代码块只有一条代码,则还有更加简洁的写法
- 引用类方法:
- 类名::类方法
- 被实现方法的全部参数传给该方法作为参数
- (a,b,...)->类名.类方法(a,b,...)
- 引用特定对象的实例方法:
- 特定对象::实例方法
- 被实现方法的全部参数传给该方法作为参数
- (a,b,...)->特定对象.实例方法(a,b,...)
- 引用某类对象的实例方法:
- 类名::实例方法
- 被实现方法的第一个参数作为调用者,后面的参数全部传给该方法作为参数
- (a,b,c,...)->a.实例方法(b,c,...)
- 引用构造器:
- 类名::new;
- 被实现方法的全部参数传给该构造器作为参数
- (a,b,...)->new 类名(a,b,...)
- 引用类方法:
- 见示例:
package testpack;
import javax.swing.JFrame;
public class Test1{
public static void main(String[] args) {
Converter c1=(String from)->{return Integer.valueOf(from);}; //Lambda表达式
Converter c2=Integer::valueOf; //引用类方法
System.out.println("c1: "+c1.convert("199")+" c2: "+c2.convert("199"));
Converter c3=(String from)->{return "ABCDEFGHIJKLMN".indexOf(from);}; //Lambda表达式
Converter c4="ABCDEFGHIJKLMN"::indexOf; //引用特定对象的实例方法
System.out.print(c3.convert("EFG"));
System.out.println(" "+c3.convert("EFG"));
Sub s1=(String str,int a,int b)->{return str.substring(a,b);}; //Lambda表达式
Sub s2=String::substring; //引用某类对象的实例方法
System.out.println(s1.sub("ABCDEFGHIJKLMN", 3, 9));
System.out.println(s1.sub("ABCDEFGHIJKLMN", 3, 9));
Frame f1=(String title)->{return new JFrame(title);}; //Lambda表达式
JFrame jf1=f1.win("我的窗口");
Frame f2=JFrame::new; //引用构造方法
JFrame jf2=f2.win("我的窗口");
System.out.println(jf1);
System.out.println(jf2);
}
}
interface Converter{
Integer convert(String from);
}
interface Sub{
String sub(String str,int a,int b);
}
interface Frame{
JFrame win(String title);
}
Lambda表达式与匿名内部类
- Lambda表达式可以在一定程度上看作是匿名内部类的子集,当匿名内部类实现的接口只有一个抽象方法(也就是函数式接口)时,可以用lambda
- 相同之处:
- 二者都可以直接访问外部类的实例变量和类变量,访问的局部变量都默认被final修饰
- 二者创建的对象,都可以调用从接口中继承的默认方法
- 见示例:
package testpack;
public class Test1{
public static void main(String[] args) {
LambdaAndInner li=new LambdaAndInner();
li.test();
}
}
class LambdaAndInner{
private int age=13;
private static String name="ABCDE";
public void test(){
String book="Java编程思想";
Display dis=new Display(){ //匿名内部类
public void display(){
System.out.println("匿名内部类对象可以直接访问,局部变量book:"+book);
System.out.println("匿名内部类对象可以直接访问,外部类的实例变量age:"+age);
System.out.println("匿名内部类对象可以直接访问,外部类的类变量name:"+name);
show(); //在匿名内部类实现抽象方法的方法体内部调用接口默认方法
}
};
dis.display();
dis.show(); //匿名内部类的对象调用接口的默认方法
}
}
interface Display{
void display();
default void show(){
System.out.println("这是接口的默认方法");
}
}
package testpack;
public class Test1{
public static void main(String[] args) {
LambdaAndInner li=new LambdaAndInner();
li.test();
}
}
class LambdaAndInner{
private int age=13;
private static String name="ABCDE";
public void test(){
String book="Java编程思想";
Display dis=()->{ //Lambda表达式
System.out.println("Lambda表达式对象,可以直接访问局部变量book:"+book);
System.out.println("Lambda表达式对象,可以直接访问外部类的实例变量age:"+age);
System.out.println("Lambda表达式对象,可以直接访问外部类的类变量name:"+name);
show(); //Lambda表达式代码块内部调用接口默认方法,编译出错
};
dis.display();
dis.show(); //Lambda表达式的对象调用接口的默认方法
}
}
interface Display{
void display();
default void show(){
System.out.println("这是接口的默认方法");
}
}
- 区别:
- 匿名内部类可以为任何接口创建实例,不管有几个抽象方法,只要都实现了就行;但Lambda只能为单抽象方法的接口创建实例
- 匿名内部类除了可以为接口创建实例,还可以是抽象类普通类;但Lambda只能函数式接口
- 匿名内部类实现抽象方法的方法体中可以调用默认方法,但Lambda代码块中不可以。见上面的示例代码
Lambda表达式的应用
- 多用于返回一个某函数式接口的对象
- 见示例:
package testpack;
import java.util.Arrays;
public class Test1{
public static void main(String[] args) {
String[] arr1=new String[]{"iOS","android","Java","C#","C","C++"};
System.out.println(Arrays.toString(arr1));
Arrays.parallelSort(arr1,(o1,o2)->o1.length()-o2.length()); //parallelSort(T[] a, Comparator<? super T> cmp)。Lambda的对象是Comparator类型
System.out.println(Arrays.toString(arr1));
int[] arr2=new int[]{2,6,-25,30,13,16};
System.out.println(Arrays.toString(arr2));
Arrays.parallelPrefix(arr2,(left,right)->left*right); // parallelPrefix(int[] array, IntBinaryOperator op)。Lambda的对象是IntBinaryOperator类型
System.out.println(Arrays.toString(arr2));
long[] arr3=new long[5];
Arrays.parallelSetAll(arr3,operand->operand*5); //parallelSetAll(long[] array, IntToLongFunction generator)。Lambda的对象是 IntToLongFunction类型
System.out.println(Arrays.toString(arr3));
//以上的Comparator、IntBinaryOperator、IntToLongFunction都是函数式接口,都有@FunctionalInterface注解
}
}
- 输出:
[iOS, android, Java, C#, C, C++]
[C, C#, iOS, C++, Java, android]
[2, 6, -25, 30, 13, 16]
[2, 12, -300, -9000, -117000, -1872000]
[0, 5, 10, 15, 20]
0028 Java学习笔记-面向对象-Lambda表达式的更多相关文章
- Java学习笔记--Java8 Lambda表达式
Java Lambda表达式入门:http://blog.csdn.net/renfufei/article/details/24600507 lambda内容的介绍:http://swiftlet. ...
- Java 学习笔记(11)——lambda 表达式
在写Java代码的时候,如果某个地方需要一个接口的实现类,一般的做法是新定义一个实现类,并重写接口中的方法,在需要使用的时候new一个实现类对象使用,为了一个简单的接口或者说为了一个回调函数就得额外编 ...
- 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用
垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...
- 0025 Java学习笔记-面向对象-final修饰符、不可变类
final关键字可以用于何处 修饰类:该类不可被继承 修饰变量:该变量一经初始化就不能被重新赋值,即使该值跟初始化的值相同或者指向同一个对象,也不可以 类变量: 实例变量: 形参: 注意可以修饰形参 ...
- 0013 Java学习笔记-面向对象-static、静态变量、静态方法、静态块、单例类
static可以修饰哪些成员 成员变量---可以修饰 构造方法---不可以 方法---可以修饰 初始化块---可以修饰 内部类(包括接口.枚举)---可以修饰 总的来说:静态成员不能访问非静态成员 静 ...
- java学习笔记06--正则表达式
java学习笔记06--正则表达式 正则表达式可以方便的对数据进行匹配,可以执行更加复杂的字符串验证.拆分.替换等操作. 例如:现在要去判断一个字符串是否由数字组成,则可以有以下的两种做法 不使用正则 ...
- java8学习笔记之lambda表达式
1.lambda表达式特点 lambda表达式可以理解为可传递的匿名函数的一种方式,无名称,但有参数列表和函数体以及返回类型,可能还有一个可抛出异常的列表. 2.lambda表达式基本语法 (para ...
- Java8新特性学习笔记(一) Lambda表达式
没有用Lambda表达式的写法: Comparator<Transaction> byYear = new Comparator<Transaction>() { @Overr ...
- 高放的c++学习笔记之lambda表达式
lambda表达式:可以让代码看起来更整洁,有些结构简单且用的次数少的函数可以用lambda表达式替代, 通常结构是这样的[捕获列表](参数列表){函数部分} 捕获列表: lambda表达式如果在一个 ...
随机推荐
- Hive启动报错: Found class jline.Terminal, but interface was expected
报错: [ERROR] Terminal initialization failed; falling back to unsupported java.lang.IncompatibleClassC ...
- Web App 向上滑动动态加载数据 2015-06-11 09:36 20人阅读 评论(0) 收藏
好久没有写博客了 - - ,个人原因 个人原因.. 宣传一下...自己的.NET群:252713569 欢迎各位大神加入 嗯..最近在公司开发微信平台的东西..需要做一个WebAPP(PS:其实就是 ...
- 对于SQL Server,我需要多少内存
经常被问到的一个问题:对于SQL Server,我需要多少内存?这个问题还是有同样的典型的“看情况而定”答案.在今天的文章里,我们来详细看下“看情况而定的”的不同方面. 全新SQL Server安装 ...
- Net设计模式实例之单例模式( Singleton Pattern)
一.单例模式简介(Brief Introduction) 单例模式(Singleton Pattern),保证一个类只有一个实例,并提供一个访问它的全局访问点.单例模式因为Singleton封装它的唯 ...
- git log命令全解析,打log还能这么随心所欲!
git log命令非常强大而好用,在复杂系统的版本管理中扮演着重要的角色,但默认的git log命令显示出的东西实在太丑,不好好打扮一下根本没法见人,打扮好了用alias命令拍个照片,就正式出道了! ...
- .NET 扩展方法 (一)
我还记得刚刚学编程的时候,老师经常会提到一句话:注意空指针.所以经常在某些“入口”位置,进行代码校验,空指针的判断就是其中的一项工作. string类型作为常用的数据类型,它在项目中出现的机率极高,所 ...
- jenkins中使用tfs插件做增量的版本发布部署
一 配置介绍 使用jenkins的tfs插件进行,源码的下载,编译,打包的操作,然后使用windows的批处理命令,在局域网内(或者本机)把打包的release包,删除掉web.config,然后靠配 ...
- C#基础-文件夹复制与删除
代码来源:http://blog.163.com/u_tommy_520/blog/static/20406104420147493933662/ 最近做MVC网站时刚好用到,用以提供一个完整的文件夹 ...
- javascript的 Object 和 Function
一. javascript 的 内置对象: Object 和 Function javascript所有东西,包括 Function 都是对象 . Array 其实是一个 Function 类型的对 ...
- 各种JS模板引擎对比数据(高性能JavaScript模板引擎)
最近做了JS模板引擎测试,拿各个JS模板引擎在不同浏览器上去运行同一程序,下面是模板引擎测试数据:通过测试artTemplate.juicer与doT引擎模板整体性能要有绝对优势: js模板引擎 Ja ...