什么是闭包? java有闭包吗?

发布于 2024-09-25 02:31:41 字数 100 浏览 4 评论 0原文

我在阅读面向对象的 Javascript 并发现了闭包的概念。我不太明白为什么以及何时使用它。像 Java 这样的其他语言也有闭包吗?我基本上想了解了解闭包的概念如何帮助我改进我的编码。

I was reading Object Oriented Javascript and found the concept of closures. I didn't quite understand why and when it is used. Do other languages like Java also have closures? I basically want to understand how knowing the concept of closures can help me improve my coding.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

離殇 2024-10-02 02:31:41

闭包是带有绑定变量的第一类函数。

大致意味着:

  • 您可以将闭包作为参数传递给其他函数
  • 闭包存储创建时存在的词法作用域中的一些变量的值

Java 最初没有对闭包的语法支持(这些是在 Java 8 中引入),尽管使用匿名内部类来模拟它们是相当常见的做法。这是一个例子:

import java.util.Arrays;
import java.util.Comparator;

public class StupidComparator { 
    public static void main(String[] args) {
        // this is a value used (bound) by the inner class
        // note that it needs to be "final"
        final int numberToCompareTo=10;

        // this is an inner class that acts like a closure and uses one bound value
        Comparator<Integer> comp=new Comparator<Integer>() {
            public int compare(Integer a, Integer b) {
                int result=0;
                if (a<numberToCompareTo) result=result-1;
                if (b<numberToCompareTo) result=result+1;
                return result;
            }
        };

        Integer[] array=new Integer[] {1,10, 5 , 15, 6 , 20, 21, 3, 7};

        // this is a function call that takes the inner class "closure" as a parameter
        Arrays.sort(array,comp);

        for (int i:array) System.out.println(i);
    }
}

A closure is a first class function with bound variables.

Roughly that means that:

  • You can pass the closure as a parameter to other functions
  • The closure stores the value of some variables from the lexical scope that existed at the time that is was created

Java initially didn't have syntactic support for closures (these were introduced in Java 8), although it was fairly common practice to simulate them using anonymous inner classes. Here's an example:

import java.util.Arrays;
import java.util.Comparator;

public class StupidComparator { 
    public static void main(String[] args) {
        // this is a value used (bound) by the inner class
        // note that it needs to be "final"
        final int numberToCompareTo=10;

        // this is an inner class that acts like a closure and uses one bound value
        Comparator<Integer> comp=new Comparator<Integer>() {
            public int compare(Integer a, Integer b) {
                int result=0;
                if (a<numberToCompareTo) result=result-1;
                if (b<numberToCompareTo) result=result+1;
                return result;
            }
        };

        Integer[] array=new Integer[] {1,10, 5 , 15, 6 , 20, 21, 3, 7};

        // this is a function call that takes the inner class "closure" as a parameter
        Arrays.sort(array,comp);

        for (int i:array) System.out.println(i);
    }
}
怀中猫帐中妖 2024-10-02 02:31:41

闭包在各种语言中有不同的名称,但要点如下:

要创建闭包,您需要一种函数类型为一等公民的语言,即它可以绑定到变量并像任何旧字符串、int 一样传递或布尔值。

您还需要能够内联声明函数。在 javascript 中,您可以执行以下操作:

foo("bar", "baz" function(x){alert("x")});

将匿名函数作为参数传递给 foo 函数。我们可以用它来创建一个闭包。

闭包“关闭”变量,因此可用于传递作用域变量。考虑这个例子:

function foo(){
    var spam = " and eggs";
    return function(food){alert(food + spam)};
}
var sideOfEggs = foo();

鸡蛋的一侧现在包含一个函数,它将“和鸡蛋”附加到它传递的任何食品上。 spam 变量是 foo 函数作用域的一部分,当函数退出时,它就会丢失,除非闭包“封闭”命名空间,只要闭包保留在内存中,就会保留它。

所以我们很清楚闭包可以访问其父级的私有范围变量,对吧?那么如何使用它们来模拟 javascript 中的私有访问修饰符呢?

var module = (function() {   
    var constant = "I can not be changed";

     return {
         getConstant    :    function() {  //This is the closure
            return constant;               //We're exposing an otherwise hidden variable here
         }
    };
}());                                     //note the function is being defined then called straight away

module.getConstant();                     //returns "I can not be changed"
module.constant = "I change you!";
module.getConstant();                     //still returns "I can not be changed" 

所以这里发生的是我们正在创建并立即调用一个匿名函数。函数中有一个私有变量。它返回一个对象,该对象具有引用该变量的单个方法。一旦函数退出, getConstant 方法就是访问变量的唯一方法。即使这种方法被删除或替换,它也不会放弃它的秘密。我们使用了闭包来实现封装和变量隐藏。有关此内容的更全面说明,请参阅 http://javascript.crockford.com/private.html

Java 还没有闭包。最接近的是匿名内部类。然而,要实例化其中一个内联对象,您必须实例化整个对象(通常来自现有接口)。闭包的美妙之处在于它们封装了简单、富有表现力的语句,这些语句在匿名内部类的噪音中有些丢失。

Closures are know by various names in various languages but the essential points are as follows:

To create closures you need a language where the function type is a 1st class citizen i.e. it can be bound to a variable and passed around like any old string, int or bool.

You also need to be able to declare functions inline. In javascript you can do something like this:

foo("bar", "baz" function(x){alert("x")});

To pass a anonymous function as a parameter to the foo function. We can use this to create a closure.

Closures "close over" variables so can be used to pass scoped variables around. Consider this example:

function foo(){
    var spam = " and eggs";
    return function(food){alert(food + spam)};
}
var sideOfEggs = foo();

The side of eggs now contains a function which appends " and eggs" to whatever foodstuff it is passed. The spam variable is part of the foo function scope and would have been lost when the function exited, except that the closure "closed over" the namespace preserving it as long as the closure remains in memory.

So we're clear on closures having access to their parent's private scoped variables right? So how about using them to simulate private access modifiers in javascript?

var module = (function() {   
    var constant = "I can not be changed";

     return {
         getConstant    :    function() {  //This is the closure
            return constant;               //We're exposing an otherwise hidden variable here
         }
    };
}());                                     //note the function is being defined then called straight away

module.getConstant();                     //returns "I can not be changed"
module.constant = "I change you!";
module.getConstant();                     //still returns "I can not be changed" 

So what's happening here is we're creating and immediately calling an anonymous function. There is one private variable in the function. It returns an object with a single method which references this variable. Once the function has exited the getConstant method is the sole way of accessing the variable. Even if this method is removed or replaced it will not give up it's secret. We have used closures to achieve encapsulation and variable hiding. For a more thorough explanation of this see http://javascript.crockford.com/private.html

Java does not have closures (yet). The closest it has are anonymous inner classes. However to instantiate one of these inline you have to instantiate an entire object (usually from an existing interface).The beauty of closures is they encapsulate simple, expressive statements which is somewhat lost in the noise of anonymous inner classes.

白云悠悠 2024-10-02 02:31:41

虽然 Java 没有一等函数,但它实际上有词法闭包。

例如,下面的 Lisp 函数(摘自 Paul Graham 的《On Lisp》一书)返回一个添加数字的函数:

(defun make-adder (n)
  (lambda (x) (+ x n))

这可以在 Java 中完成。但是,由于它没有一等函数,因此我们需要定义一个接口(我们称之为 Adder)和一个带有实现该接口的函数的匿名内部类。

public interface Adder {
    int add(int x);
}

public static Adder makeAdder(final int n) {
    return new Adder() {
        public int add(int x) {
            return x + n;
        }
    };
}

内部 add() 函数是一个词法闭包,因为它使用外部词法范围中的 n 变量。

为此,必须将变量声明为final,这意味着该变量无法更改。然而,改变参考变量中的值是可能的,即使它们是最终的。例如,考虑以下 Lisp 函数(也来自 On Lisp):

(defun make-adderb (n)
  (lambda (x &optional change)
    (if change
        (setq n x)
        (+ n n))))

这可以通过将外部变量包装在引用类型变量(例如数组或对象)中来在 Java 中实现。

public interface MutableAdder {
    int add(int x, boolean change);
}

public static MutableAdder makeAdderB(int n) {
    final int[] intHolder = new int[] { n };
    return new MutableAdder() {
        public int add(int x, boolean change) {
            if (change) {
                intHolder[0] = x;
                return x;
            }
            else {
                return intHolder[0] + x;
            }
        }
    };
}

我会声称这是真正的词汇闭包,而不是模拟。但我不会说它很漂亮。

While Java doesn't have first-class functions, it does in fact have lexical closures.

For instance, the following Lisp function (stolen from Paul Graham's book On Lisp) returns a function that adds a number:

(defun make-adder (n)
  (lambda (x) (+ x n))

This can be done in Java. However, since it doesn't have first-class functions, we need to define an interface (let's call it Adder) and an anonymous inner class with a function that implements this interface.

public interface Adder {
    int add(int x);
}

public static Adder makeAdder(final int n) {
    return new Adder() {
        public int add(int x) {
            return x + n;
        }
    };
}

The inner add() function is a lexical closure because it uses the n variable from the outer lexical scope.

The variable had to be declared final in order to do this, which means that the variable cannot change. However, changing values within reference variables is possible, even if they are final. For instance, consider the following Lisp function (also from On Lisp):

(defun make-adderb (n)
  (lambda (x &optional change)
    (if change
        (setq n x)
        (+ n n))))

This can be implemented in Java by wrapping the outer variable in a reference type variable, such as an array or object.

public interface MutableAdder {
    int add(int x, boolean change);
}

public static MutableAdder makeAdderB(int n) {
    final int[] intHolder = new int[] { n };
    return new MutableAdder() {
        public int add(int x, boolean change) {
            if (change) {
                intHolder[0] = x;
                return x;
            }
            else {
                return intHolder[0] + x;
            }
        }
    };
}

I will claim that this is real lexical closures, not a simulation. But I won't claim that it's pretty.

倾`听者〃 2024-10-02 02:31:41

闭包是一种范围界定技术。 Java 没有闭包。

在 javascript 中,您可以执行如下操作:

var scope = this;

var f = function() {
    scope.somethingOnScope //scope is 'closed in' 
}

如果您执行类似将 f 传递给函数的操作,则范围是定义它的范围。

A closure is a scoping technique. Java does not have closures.

In javascript you can do something like that following:

var scope = this;

var f = function() {
    scope.somethingOnScope //scope is 'closed in' 
}

if you then do something like pass f to a function, scope is the scope of where it was defined.

紫南 2024-10-02 02:31:41

闭包是一个非常自然的功能,它允许自由变量被其词法环境捕获。

这是 javascript 中的一个示例:

function x() {

    var y = "apple";

    return (function() {
         return y;
    });
}

函数 x 返回一个函数。请注意,当创建函数时,该函数中使用的变量不会像我们返回表达式时那样进行计算。创建函数时,它会查看哪些变量不是函数的本地变量(自由)。然后,它找到这些自由变量并确保它们不会被垃圾回收,以便在函数实际调用时可以使用它们。

为了支持这个特性,你需要有java不支持的一流函数。

请注意,这是我们在 JavaScript 等语言中拥有私有变量的一种方式。

Closure is a very natural feature that allows free-variables to be captured by their lexical environment.

here's an example in javascript:

function x() {

    var y = "apple";

    return (function() {
         return y;
    });
}

function x returns a function. note that when a function is created variables used in this function are not evaluated like when we return an expression. when the function is created it looks to see what variables are not local to the function (free). It then locates these free variables and ensures they are not garbage collected so that they can be used once the function is actually called.

In order to support this feature you need to have first-class functions which java does not support.

Note this is a way we can have private variables in languages like JavaScript.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文