第一章.java&golang的区别之:闭包

对于golang一直存有觊觎之心,但一直苦于没有下定决心去学习研究,最近开始接触golang。就我我的来讲,学习golang的原动力是由于想要站在java语言以外来审视java和其它语言的区别,再就是想瞻仰一下如此NB的语言。年前就想在2019年作一件事情,但愿能从各个细节处作一次java和golang的对比分析,不评判语言的优劣,只想用简单的语言和能够随时执行的代码来表达出二者的区别和底层涉及到的原理。今天是情人节,馒头妈妈在加班,送给本身一件贴心的礼物,写下第一篇对比文章:java&golang的区别之:闭包。
关于闭包究竟是啥,建议参考知乎上的解释: https://www.zhihu.com/question/51402215/answer/556617311

  • java8以前的闭包
在java8以前,java其实就已经对闭包有了必定层面的支持,实现的闭包方式主要是靠匿名类来实现的,下面是java程序员常常写的一段代码:
 1 public class ClosureBeforeJava8 {  2     int y = 1;  3 
 4     public static void main(String[] args) {  5         final int x = 0;  6         ClosureBeforeJava8 closureBeforeJava8 = new ClosureBeforeJava8();  7         Runnable run = closureBeforeJava8.getRunnable();  8         new Thread(run).start();  9  } 10 
11     public Runnable getRunnable() { 12         final int x = 0; 13         Runnable run = new Runnable() { 14  @Override 15             public void run() { 16 
17 System.out.println("local varable x is:" + x); 18 //System.out.println("member varable y is:" + this.y); //error 19 } 20 }; 21 return run; 22 } 23 }

上段代码的输出:local varable x is:0html

在代码的第13行到第20行,经过匿名类的方式实现了Runnable接口的run()方法,实现了一部分操做的集合(run方法),并将这些操做映射为java的对象,在java中就能够实现将函数以变量的方式进行传递了,若是仅仅是传递函数指针,那还不能算是闭包,咱们再注意第17行代码,在这段被封装能够在不一样的java对象间传递的代码,引用了上层方法的局部变量,这个就有些闭包的意思在里面了。可是第18行被注释掉的代码在匿名类的状况下却没法编译经过,也就是封装的函数里面,没法引用上层方法所在对象的成员变量。总结一下,java8以前的闭包特色以下:java

1.能够实现封装的函数在jvm里进行传递,能够在不一样的对象里进行调用;程序员

2.被封装的函数,能够调用上层的方法里的局部变量,可是此局部变量必须为final,也就是不能够更改的(基础类型不能够更改,引用类型不能够变动地址);golang

3.被封装的函数,不能够调用上层方法所在对象的成员变量;
  • java8里对闭包的支持

java8里对于闭包的支持,其实也就是lamda表达式,咱们再来看一下上段代码在lamda表达式方式下的写法:多线程

 1 public class ClosureInJava8 {  2     int y = 1;  3 
 4     public static void main(String[] args) throws Exception{  5         final int x = 0;  6         ClosureInJava8 closureInJava8 = new ClosureInJava8();  7         Runnable run = closureInJava8.getRunnable();  8         Thread thread1 = new Thread(run);  9  thread1.start(); 10  thread1.join(); 11         new Thread(run).start(); 12  } 13 
14     public Runnable getRunnable() { 15         final int x = 0; 16         Runnable run = () -> { 17              
18 System.out.println("local varable x is:" + x); 19 System.out.println("member varable y is:" + this.y++); 20 }; 21 return run; 22 } 23 }

 上面对代码输出:闭包

local varable x is:0
member varable y is:1
local varable x is:0
member varable y is:2并发

在代码的第16行到第20行,经过lamda表达式的方式实现了函数的封装(关于lamda表达式的用法,你们能够自行google)。经过代码的输出,你们能够发现,在lamda表达式的书写方式下,封装函数不但能够引用上层方法的effectively final类型(java8的特性之一,其实也是final类型)的局部变量,还能够引用上层方法所在对象的成员变量,并能够在其它线程和方法中对此成员变量进行修改。总结一下:java8对于闭包支持的特色以下:jvm

1.经过lamda表达式的方式能够实现函数的封装,并能够在jvm里进行传递;ide

2.lamda表达式,能够调用上层的方法里的局部变量,可是此局部变量必须为final或者是effectively final,也就是不能够更改的(基础类型不能够更改,引用类型不能够变动地址);函数

3.lamda表达式,能够调用和修改上层方法所在对象的成员变量;
因为还没时间分析jdk和hotspot的源码,在此只能猜想推理,第2点和第3点的状况。关于第2点:上层方法的局部变量必须是final修饰的,网上的文章大部分都是说由于多线程并发的缘由,没法在lamda表达式里进行修改上层方法的局部变量,这点上我是不一样意这个观点的。我认为主要缘由是:java在定义局部变量时,对于基础类型都是建立在stack frame上的,而一个方法执行完毕后,此方法所对应的stack frame也就没有意义了,试想一下,lamda表达式所依赖的上层方法的局部变量的存储区(stack frame)都消失了,咱们还怎么可以修改这个变量,这是毫无心义的,在java里也很难实现这一点,除非像golang一下,在特定状况下,更改局部变量的存储区域(在heap里存储)。关于第3点:实现起来就比较容易,就是在lamda表达式的对象里,建立一个引用地址,地址指向原上层方法所在对象的堆存储地址便可。
  • golang里对闭包的支持

golang里对于闭包的支持,理解起来就很是容易了,就是函数能够做为变量来传递使用,代码以下:

 1 package main  2 
 3 import "fmt"
 4 
 5 func main() {  6     ch := make(chan int ,1)  7     ch2 := make(chan int ,1)  8     fn := closureGet()  9  go func() { 10  fn() 11         ch <-1
12  }() 13  go func() { 14  fn() 15         ch2 <-1
16  }() 17     <-ch 18     <-ch2 19 } 20 
21 func closureGet() func(){ 22     x := 1
23     y := 2
24     fn := func(){ 25         x = x +y 26         fmt.Printf("local varable x is:%d y is:%d \n", x, y) 27  } 28     return fn 29 }

代码输出以下:

local varable x is:3 y is:2
local varable x is:5 y is:2

代码的第24行到27行,定义了一个方法fn,此方法可使用上层方法的局部变量,总结一下:

1.golang的闭包在表达形式上,理解起来很是容易,就是函数能够做为变量,来直接传递;

2.golang的封装函数能够没有限制的使用上层函数里的局部变量,而且在不一样的goroutine里修改的值,都会有所体现。

关于第2点,你们能够参考文章:https://studygolang.com/articles/11627  中关于golang闭包的讲解部分。

  • 总结

golang的闭包从语言的简洁性、理解的难易程度、支持的力度上来讲,确实仍是优于java的。本文做为java和golang对比分析的第一篇文章,因为调研分析的时间有限,不免有疏忽之处,欢迎各位指正。

原文出处:https://www.cnblogs.com/mantu/p/10381316.html

相关文章
相关标签/搜索