java闭包
1. 闭包的语法结构
Groovy的闭包
闭包(Closure)是java所不具备的语法结构(JAVA8增加了对闭包的支持)。闭包就是一个代码块,用“{ }”包起来。此时,程序代码也就成了数据,可以被一个变量所引用(与C语言的函数指针比较类似)。闭包的最典型的应用是实现回调函数(callback)。Groovy的API大量使用闭包,以实现对外开放。闭包的创建过程很简单,例如:
{ 参数 ->
代码...
}
参考下面的例子代码,定义了c1和c2两个闭包,并对它们进行调用:
def c1 = { println it }
def c2 = { text -> println text }
c1.call(content1) //用call方法调用闭包
c2(content2) //直接调用闭包
“->;”之前的部分为闭包的参数,如果有多个参数,之间可用逗号分割;“->;”之后的部分为闭包内的程序代码。如果省略了“->;”和它之前的部分,此时闭包中代码,可以用名为“it”的变量访问参数。
闭包的返回值和函数的返回值定义方式是一样的:如果有return语句,则返回值是return语句后面的内容;如果没有return语句,则闭包内的最后一行代码就是它的返回值。
2. java开发的缺点有哪些
我认为Java语言的10大问题是:
1、缺少闭包(closure):我想这个不需要解释了。函数式编程已经存在几十年了,但最近几年,它们获得了越来越多的关注,最主要的原因,是它可以自然地编写并行程序。我部分的同意Joshua Bloch强调在Java中引入闭包的问题需要再想一想(BGGA提议的方式真的很糟),至少闭包的缺失,使得在Java中做任何真正的函数式编程都是不可能的。
2、缺少一等函数:这个问题与前一个有些关联,但我认为它更糟糕。在Java里,要达到类似效果的唯一方式,是使用着名的、丑陋悲惨的单方法匿名内部类,但这看上去的确是一个拙劣的方法。甚至在C#中,也通过代理机制,提供了一个更好的实现。
3、原生类型(Primitive types):如果在Java中一切皆对象,那是多么完美啊,但他们偏偏不这样设计。因而,这一点导致了一些问题,比如,不能把一个int放到集合(Collection)里,这个在Java5中通过自动装箱特性得到了解决(下面会提到)。它也造成了传值与传引用上的困扰,原生类型数据是通过值传给方法的(复制一份拷贝,然后传给函数),而真正的对象是通过传递(译注:其实是复制对象地址再传递,因此应该也是传值方式,只是由于函数内部可通过这个对象地址访问对象,因此效果上类似传引用)。
4、自动装箱(Autoboxing)和自动拆箱(autounboxing):这个特性是为了解决因原生类型的存在所导致的问题,在Java5引入的。它允许静默地转换原生类型到相应的对象,但这常常导致其它的问题。比如Integer可以为null,但int不能,因此这时JVM只能抛出一个难以调试的空指针异常(NullPointerException)。此外,它还可能导致其它奇怪的行为,就像下面的例子,我们就很难理解,变量test为什么是false:
Intger a = new Integer(1024);
Intger b = new Integer(1024);
boolean test = a < b || a == b || a > b;
5、缺少范型具类化:范型是Java5引入的一个很酷的特征,但是为了保持与旧版本Java的兼容性,导致缺失某些重要的特性,尤其是不能在运行时反省范型的类型。例如,你有一个方法,接受List参数,如果传进来一个List,你却不能知道运行里该范型的确切类型。同理,你也不能创建范型数组。这意味着,尽管下面的代码看起来很自然,但却不编译不了:
List[] listsOfStrings = new List[3];
6、不可避免的范型警告:你有发现过自己陷入不可能去掉的关于范型的警告么?如果你像我一样大量使用范型,我打赌你碰到过。事实上,是这个问题的规模化症状,让他们认为需要引入一个特定的注解(@SuppressWarnings("unchecked"))来处理这种情况,我觉得,范型应该可能被设计的更好。
7、不能传void给方法调用:我得承认,这种给方法传递void的需求,乍一看有些怪异。我喜欢DSL,当我实现自己的DSL库(lambdaj)的一个特定特性时,我不得不需要一个方法声明成这样的签名:void doSomething(Object parameter),这里为这个方法传进来的参数parameter,是另一个方法调用的结果,它唯一的目的,是注册调用(的对象)自身,以可以在以后执行它。让我吃惊的是,即使println方法返回void,看上去也并没有一个好理由,不允许我把代码写成这样,:
doSomething(System.out.println("test"));
8、没有原生的代理机制:代理是一种非常有效和应用广泛的模式,但Java提供的代理机制,只针对接口,而不是具体类。这是为什么象cblib这样提供这种机制的库,被如此多的主流框架,如Spring和Hibernate,采用的原因。此外,由于cglib通过运行时创建被代理类的子类来实现的,因此这些种方式有一个众所周知的限制——不能代理final类,比如String。
9、差劲的Switch...case语句:Java规定,switch...case只能选择int和enum(Java5开始)。这一点如果跟更现代的语言如Scala相比,看起来简直太弱了。
10、受检查异常(Checked exception):类似原生类型,受检查异常也已经成为Java的一个罪孽之源。它迫使程序员必须做下面两件极其糟糕讨厌的事情中的一个:让你的代码里充斥大量的、糟糕难读的、容易出错的try...catch语句,而这样做的最大意义,只是将捕获的异常,包装成运行时异常,然后再重新抛出;或者是让大量的抛出声明子句污染你的API,让接口缺少灵活性和可扩展性。
真正的问题是,这里我提到的这几大主要问题,唯一的解决办法,是要做一个痛苦的决择,定义一套新的语言规范,放下当前版本的向后兼容性。我猜他们永远也不会这么做,虽然我相信,如果编写一个能够自动转换旧Java源码的程序,让它们与假设的新版本兼容,并不是很困难。最后,这就是我决定开始寻找一个更好的JVM兼容语言的原因。
3. java8的特性有哪些
Lambda表达式(也称为闭包)它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理
Java 8使用两个新概念扩展了接口的含义:默认方法和静态方法。
方法引用使得开发者可以直接引用现存的方法、Java类的构造方法或者实例对象。方法引用和Lambda表达式配合使用,使得java类的构造方法看起来紧凑而简洁,没有很多复杂的模板代码。
重复注解,Java 8中使用@Repeatable注解定义重复注解
Java 8编译器在类型推断方面有很大的提升,在很多场景下编译器可以推导出某个参数的数据类型,从而使得代码更为简洁。
Java 8拓宽了注解的应用场景。
Java 8增加了很多新的工具类(date/time类),并扩展了现存的工具类,以支持现代的并发编程、函数式编程等。
4. 什么是闭包
闭包是编程中一个关键概念,简单来说,它是能够在外部访问并操作内部函数变量的函数。在JavaScript中,由于函数作用域的特性,只有内部函数能访问局部变量,因此闭包可以理解为“定义在函数内部的函数”。实际上,闭包通过连接函数内部和外部环境,创建了一种持久的“数据包”,即使外部函数执行完毕,内部变量仍然有效,因为它们被闭包持有。
闭包的存在在多种编程语言中都有体现,包括PHP、Scala、Groovy、Java(从Java 8开始)、Python、Ruby等,它们支持不同程度的闭包功能。闭包的定义涉及集合的闭包性质,如集合的闭包定义为包含自身且满足特定运算条件的子集,而闭包的特性如最小闭集、包含关系等,是其核心概念。
在实际应用中,闭包常用于模拟私有变量、实现回调函数、以及维护函数作用域内的状态。例如,闭包可以用来创建计数器,或者在函数返回内部函数以保护变量不被外部访问。同时,JavaScript的垃圾回收机制与闭包紧密相关,当一个函数返回一个内部函数时,外部函数的作用域会被保留,避免了资源的过早释放。
理解闭包需要掌握函数执行环境、活动对象、作用域和作用域链的概念。在内存管理上,要谨慎使用闭包,避免内存消耗过大和可能的内存泄露问题。此外,正确处理闭包中变量的修改是关键,特别是在将闭包作为对象方法时,避免意外改变父函数的内部变量。
闭包在数学上也有其应用,比如在离散数学中,关系的闭包是通过添加额外有序对来增强原有关系的性质,而在拓扑学中,闭包概念扩展到邻域和集合子集的包含关系。总之,闭包是一个强大而复杂的概念,它在编程和数学领域都发挥着重要作用。