JDK8.0学习体会--从python的lambda类比java的lambda

*

JDK8.0学习体会–从python的lambda类比java的lambda*

小菜最近接触jdk8.0学习下还是有不少新东西的。这里记录下自己的学习心得。
小菜的理解可能是错误的,还请大家斧正。共同进步。

No0.eclipse的要求
不是每个eclipse的版本都可以使用jdk8.0的。
从KeplerSR2开始才能支持这个jdk8.0.干脆直接用一个支持的。比如Mars 1

No1.接口的默认方法
给接口增加默认的default方法,虽然容易理解,但是总感觉画蛇添足。接口就应该是纯抽象行为的规范定义。增加一个默认接口函数还不是给这个接口的实现类来调用。如果实现类使用这个方法来作为借口抽象方法的实现,那不就暴露了隐藏实现的原则了吗。搞不懂!!!
也许它的存在是这样的一种情况,接口中用多个抽象方法,每次实现起来如果用适配器模式是很麻烦的。使用这个默认方法可以演示出接口默认的行为。
至于实际使用的时候,那就自己发挥了。
No2.lambda表达式
这个东西来源于函数编程,为了书写匿名函数而用的。
java用它也只是形式主义。因为java中函数是不能独立存在的。
最近学习python的时候接触到的定义是:

def add(x,y):
    return x+y

使用这个lambda来书写上面的函数就是

 z = lambda x,y: x+y

调用: z(1,2)
可见lambda不用指定函数名,而且 关键字 lambda后面就是参数列表可以加括号。 冒号是python的块符号。后面就是函数体代码了。
python的lambda函数体就是一个return语句。return是不能显示写出来的。

由python的例子类比下java的lambda
python中函数也是对象,可以单独存在。
然而java中只能以对象存在的模式,导致它不可能照猫画虎直接用类似
lambda (参数列表) {代码体}得到java的。
python用lambda返回一个匿名函数,那么java就返回一个匿名对象。

那么java怎么弄呢?注意java中也有匿名的概念。匿名内部类。干什么用的?
它的存在和这个lambda很相似.
比如我们实现一个Runnable接口的时候使用匿名内部类

        Runnable rn = new Runnable() {
            public void run() {
                System.out.println("run ");
            }
        };

不知大家发现了没 等号两边的 接口类型是一样的,都是Runnable
如果这样我们完全可以用等号左边的接口,等号右边的接口以及方法我们完全可以根据等号左边的东西来得到。
剩下的只是需要一个机制将等号右边的东西自动生成即可。那么上面的代码如果我们认为有一个机制可以生成右边的代码,上面的代码变成了如下的形式:

Runnable rn2 = () 代码生成机制部分 {
            System.out.println("run2 ");
        };

也就是说接口是一样的缘故我们可以省略的东西有:接口以及接口内部的方法头
这样一来我们就看到了Java的lambda表达式的雏形了。
这个代码生成的机制就是这个符号 ->
我们的Runnable实现的lambda表达式就是:

        Runnable rn2 = () -> {
            System.out.println("run2 ");
        };

可以看到符号->可以自动生成代码头部分。
那么我们得到Java lambda的结构式:

接口类型  接口变量  =  接口方法参数列表  -> {接口方法实现体}

如果参数为空就只写一个()就可以了
如果只有一个参数那么参数的括号也不用写
至于参数的类型可以指定,也可以不指定。
如果方法实现体可以一句写完就不用这个{}来限制了。

例如如下的代码片段:

Action.java
    public interface Action<I> {
        void execute(I in);
    }
Main.java中的main方法内测试:
Action<String> action = in -> System.out.println(in);
action.execute("lambda !"); 

可见java的lambda是在匿名内部类的基础上得来的。
因此lambda对于变量的访问以及作用域和内部类是一致的。
但是,它有一个限制,接口中只能存在一个抽象方法。不然多了 ->可不能全部
生成。这个默认的前提导致我们的下一个特性:函数式接口。
要求接口里面只能存在一个抽象方法。

No3.函数式接口
要给你的接口添加 @FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。
以前java7中的接口,如果只有一个抽象方法的有的已经加上了这个注解。
例如上面的Runnable它就被加上注解了。但是AWT中的ActionListener可没有加哦。这个很好理解。

@FunctionalInterface
public interface Converter<O, I> {
    O convert(I in);
}

No4.方法与构造函数引用
这个如果理解了lambda之后就不难理解了。只不过这个只是方法或者构造函数的引用。我们用引用的方法来完成我们的抽象方法。
但是这个表达式返回的仍是这个接口的实现对象。不是方法的返回值。
语法格式是

接口类型 变量 =  引用类::引用方法
使用   引用类::引用方法来完成我们接口的抽象方法的实现。
同样这个接口也要求只能有一个抽象方法。

例如下面的java代码

Converter.java
    @FunctionalInterface
    public interface Converter<O, I> {
        O convert(I in);
    }

ConverterFactory.java
    public interface  ConverterFactory<Type> {
        public abstract Type create();
    }

ConverterImpl.java
    public class ConverterImpl implements  
        Converter<Integer, String> {
        @Override
        public Integer convert(String in) {
            return Integer.parseInt(in);
        }
    }

Main.java
    public static void main(String[] args) {
        //对于接口的create方法使用ConverterImpl的构造函数实现
        ConverterFactory<ConverterImpl> 
            factory =   ConverterImpl::new;
        //返回一个ConverterImpl对象
        Converter<Integer, String> 
             converter1 = factory.create();
        //调用ConverterImpl的convert方法
        Integer it = converter1.convert("123");
        System.out.println(it + 200);
    }

其他的特性都是一些接口的介绍。
可以参考如下文章:
JAVA8 十大新特性详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值