What is the difference between Java 8 Lambda constructs and JavaScript?

I need to convert Java 8 code to JavaScript (one way, once in a lifetime). To speed things up, I want to automate and use the test suite as much as possible to fix all remaining problems.

I wonder what is the difference between Java 8 lambdas and JavaScript (functions)?

Any important incompatibilities?

+5
source share
2 answers

One important thing to keep in mind when comparing Java lambdas and JS functions is how both fields of vision span.

In Java, lambdas can only efficiently use final variables and display only those that are explicitly needed. In JS, functions can access all variables in all parent closures and thus capture everything.

The result of this is the possibility of a memory leak if you do not know what you are doing. As an example:

IntSupplier getSupplier(MyMemoryHeavyClass heavy) { int x = heavy.hashCode(); return () -> x; } 

This method will return a lambda that actually contains only int. There is no problem. However, the naive translation into JavaScript ...

 function getSupplier(heavy) { var x = heavy.hashCode(); return function() { return x; }; } 

This may not be obvious at first glance, but it has a serious problem. A function expression will capture ALL within the scope, including the heavy parameter (even if it is not referenced inside the returned function). As a result, it prevents heavy collection (which in this example requires a large amount of memory) from garbage collection and thus remains in memory as long as the return function exists.

EDIT

As stated in the comments, this information may be a bit outdated, as modern engines look more reasonable. The V8, for example, will apparently only capture what it considers necessary. However, it can still be fooled, since all functions created in the same scope have the same closure.

For example, adding a string (function y() { return heavy; }); , which otherwise would mean nothing, will force heavy to close the same as return x; creating a leak.

Although it’s far-fetched in this particular example, it’s far from unbelievable that similar problems can occur with the naive translation of Java methods containing multiple lambdas.

+5
source

One significant difference between JavaScript functions / arrow expressions and the anonymous Java / lambdas classes is that the latter (Java) cannot reassign captured variables and parameters, since they are completely considered in Java 8 (in previous versions of Java, all declared variables and parameters must be declared final ). There are several ways around this limitation:

  • Use the special Mutable<T> methods with set and get , since the Mutable<?> Instance can be passed as a captured variable or parameter.
  • Use, say, AtomicReference<T> or some similar Atomic*** methods (if I'm right, this approach cannot be used in GWT).
  • Use an array of elements as a value field, since array elements can be easily reassigned, say Object[] o = {null} . Although this solution turned out to be lower and requires careful reassignment / reference via indexes, it can have the following advantages: 1) It is well versed in primitive types (say, new int[1] definitely better than Mutable<Integer> ) . 2) An array can contain more than one value (say, your lambda expression may want to change the captured r , g and b , and the triple can be wrapped in float[] rgb = new float[3] , where rgb[0] can be r ) This workaround, if I am right, is the intended intent in IntelliJ IDEA.

So, if you have code with workarounds above in your Java code, you can try to get rid of these workarounds when porting to JavaScript. Let's say the following Java code with a primitive array field

 final float rgb[] = new float[3]; final Runnable whiteOut = () -> { rgb[0] = 255; rgb[1] = 255; rgb[2] = 255; }; final Runnable blackOut = new Runnable() { @Override public void run() { rgb[0] = 255; rgb[1] = 255; rgb[2] = 255; } }; whiteOut.run(); blackOut.run(); 

can be easily translated into cleaner JavaScript (if you're ok with separate r , g and b ):

 var r, g, b; var whiteOut = () => { r = 255; g = 255; b = 255; } var blackOut = function() { r = 0; g = 0; b = 0; } whiteOut(); blackOut() 
+3
source

Source: https://habr.com/ru/post/1241480/


All Articles