kotlin/jvm jdk8 not support code
var buffer = StringBuffer();
var arr = arrayOf("1","2","3","4");
arr.forEach {buffer::append}
error info
java jdk8 supported code,
String[] b = new String[]{"c", "b"};
Arrays.stream(b).forEach(buffer::append);
In general, If you want to pass a method reference (buffer::append) to a method that takes a lambda, you need to enclose it in parentheses, not curly braces. In this specific case, you can't pass the append method as a method reference, because it returns StringBuilder, and forEach requires a method that returns Unit.
To make your code work, use a lambda:
arr.forEach { buffer.append(it) }
You can't copy-paste and use Stream code like that, because it ends up parsing it wrong. Since foreach blocks also contain the data, you can just do:
var buffer = StringBuffer();
var arr = arrayOf("1","2","3","4");
arr.forEach{buffer.append(it)}
The forEach block doesn't take a method as an argument, so doing buffer::append doesn't add any data, since you have to do that yourself
Related
I worked with Kotlin's Regex API to get occurences of some regular expression. I wanted to convert the finding directly into another object so I intuitively used map() on the result sequence.
I was very surprised that the map function is never called but forEach is working. This example should make it clear:
val regex = "a.".toRegex()
val txt = "abacad"
var counter = 0
regex.findAll(txt).forEach { counter++ }
println(counter) // 3
regex.findAll(txt).map { counter++ }
println(counter) // still 3 since map is not called
regex.findAll(txt).forEach { counter++ }
println(counter) // 6
My question is why? Did I oversee it in the documentation?
(tested on Kotlin 1.5.30)
findAll() returns a Sequence<MatchResult>. Operations on Sequence are classified either as intermediate or terminal. The documentation for the functions declares which type they are. map and onEach are intermediate. Their action is deferred until a terminal operation is made. forEach is terminal.
Manipulating a Sequence with map returns a new Sequence that will perform the mapping function only when it is actually iterated, such as by a call to forEach or using it in a for loop.
This is the purpose of Sequence, to defer mutating functional calls. It can reduce allocations of intermediate Lists, or in some cases avoid applying the mutations on every single item, such as if the terminal call in the chain is a find() call.
I am new to Java 8 and was trying to rewrite an existing code snippet logic using the Java 8 features.
However I am not sure how to use an existing arrayList defined outside the block to get values from it when it is placed inside the lambda block. It complains that it has to be final or effectively final.
I started with converting the inner traditional for loop and encountered the same issues with a counter variable which I was able to sort using AtomicInteger but am not sure how to do that for arrayList as well as I cannot also define the arrayList inside the lambda block since it has a dependency of an i variable that is present in the outer while loop.
Any help will be much appreciated !!! Thanks in advance.
Below is my code snippet :-
public String somemethod(ArrayList someValues){
int i=0;
String status="Failed";
ArrayList someOtherValues = new ArrayList();
try
{
while ( i < (someValues.size()))
{
someOtherValues = (ArrayList) someValues.get(i);
someOtherValues.replaceAll(t -> Objects.isNull(t) ? "" : t); //converting every null to "" within the arrayList someOtherValues
int count=4;
AtomicInteger counter=new AtomicInteger(5);
if(!someOtherValues.get(0).toString().equals(""))
{
while ( count < (someOtherValues.size()))
{
IntStream.range(0, 3).forEach(k -> {
someObjectClass someObject=new someObjectClass();
someOtherObjectClass id = new someOtherObjectClass(someOtherValues.get(0).toString(),someOtherValues.get(count).toString()) //Line where the error is
someObject=new someObjectClass(id);
someObject.setId(id);
if(someCondition)
{
try
{
someObject.setSomething(someValue);
counter.incrementAndGet()
}
}
someObject.setsomeOtherValues1(someOtherValues.get(1).toString());
someObject.setsomeOtherValues2(someOtherValues.get(3).toString())
}
count=counter.get();
counter.incrementAndGet();
}
}
i++;
}
catch(Exception e)
{
return status;
}
}
Right now where it is pending is it complains that someOtherValues, which is an existing arrayList defined outside the lambda block needs to be final or effectively final in order to fetch elements.
Is it literally not possible to change/optimize the above function into a fewer lines of code using Java 8 streams/lambdas/forEach ?
As a general rule it is not a good idea to try and change outside variables inside a lambda definition. But since Java's very loose concept of final fields and variables only applies to assigning values, it can still be done.
The only thing you cannot do in a lambda expression with variable defined outside is assigning new values.
So this does not compile:
List<String> lst = new ArrayList<>();
myLambda = e -> {
lst = new ArrayList<>(); //this violates the 'final' rule
lst.add(e);
}
It is however possible to call any method of the outside variable, even if it changes the state of the variable. This will work:
myLambda = e -> {
lst.add(e);
}
Even though you're still changed the state of the variable lst, this is legal code.
But I strongly advise against it. Lambdas are meant to used in a functional matter and should not change any variables defined elsewhere. It's a better choice to create a list inside the lambda, return it from the lambda and then add it to the outside list.
Is there an operator that allows to process result/success whether or not Mono is empty. For example:
Mono<Bar> result = sourceMono.flatMap(n -> process(n)).switchIfEmpty(process(null));
where:
Mono<Bar> process(Foo in){
Optional<Foo> foo = Optional.ofNullable(in);
...
}
is there a shortcut operator that allows something like below or similar?
Mono<Bar> result = sourceMono.shortCut(process);
More specifically, mono.someOperator() returns Optional<Foo> which would contain null when Mono is empty and have value otherwise.
I wanted to avoid to create process method as mentioned above and just have a block of code but not sure which operator can help without duplicating block.
There is no built-in operator to do exactly what you want.
As a workaround, you can convert the Mono<Foo> to a Mono<Optional<Foo>> that emits an empty Optional<Foo> rather than completing empty, and then operate on the emitted Optional<Foo>.
For example:
Mono<Bar> result = fooMono // Mono<Foo>
.map(Optional::of) // Mono<Optional<Foo>> that can complete empty
.defaultIfEmpty(Optional.empty()) // Mono<Optional<Foo>> that emits an empty Optional<Foo> rather than completing empty
.flatMap(optionalFoo -> process(optionalFoo.orElse(null)));
As per above #phil's workaround, here is a reusable function:
private final <T> Mono<Optional<T>> afterSucess(Mono<T> source) {
return source
.map(Optional::of) //
.defaultIfEmpty(Optional.empty());
}
then invoke in publisher line:
Foo<Bar> result = fooMono
.transformDeferred(this::afterSucess)
.flatMap(optionalFoo -> process(optionalFoo.orElse(null)));
var take = R.curry(function take(count, o) {
return R.pick(R.take(count, R.keys(o)), o);
});
This function takes count keys from an object, in the order, in which they appear. I use it to limit a dataset which was grouped.
I understand that there are placeholder arguments, like R.__, but I can't wrap my head around this particular case.
This is possible thanks to R.converge, but I don't recommend going point-free in this case.
// take :: Number -> Object -> Object
var take = R.curryN(2,
R.converge(R.pick,
R.converge(R.take,
R.nthArg(0),
R.pipe(R.nthArg(1),
R.keys)),
R.nthArg(1)));
One thing to note is that the behaviour of this function is undefined since the order of the list returned by R.keys is undefined.
I agree with #davidchambers that it is probably better not to do this points-free. This solution is a bit cleaner than that one, but is still not to my mind as nice as your original:
// take :: Number -> Object -> Object
var take = R.converge(
R.pick,
R.useWith(R.take, R.identity, R.keys),
R.nthArg(1)
);
useWith and converge are similar in that they accept a number of function parameters and pass the result of calling all but the first one into that first one. The difference is that converge passes all the parameters it receives to each one, and useWith splits them up, passing one to each function. This is the first time I've seen a use for combining them, but it seems to make sense here.
That property ordering issue is supposed to be resolved in ES6 (final draft now out!) but it's still controversial.
Update
You mention that it will take some time to figure this out. This should help at least show how it's equivalent to your original function, if not how to derive it:
var take = R.converge(
R.pick,
R.useWith(R.take, R.identity, R.keys),
R.nthArg(1)
);
// definition of `converge`
(count, obj) => R.pick(R.useWith(R.take, R.identity, R.keys)(count, obj),
R.nthArg(1)(count, obj));
// definition of `nthArg`
(count, obj) => R.pick(R.useWith(R.take, R.identity, R.keys)(count, obj), obj);
// definition of `useWith`
(count, obj) => R.pick(R.take(R.identity(count), R.keys(obj)), obj);
// definition of `identity`
(count, obj) => R.pick(R.take(count, R.keys(obj)), obj);
Update 2
As of version 18, both converge and useWith have changed to become binary. Each takes a target function and a list of helper functions. That would change the above slightly to this:
// take :: Number -> Object -> Object
var take = R.converge(R.pick, [
R.useWith(R.take, [R.identity, R.keys]),
R.nthArg(1)
]);
Since getting started in Dart I've been watching for a way to execute Dart (Text) Source (that the same program may well be generating dynamically) as Code. Like the infamous "eval()" function.
Recently I have caught a few hints that the communication port between Isolates support some sort of "Spawn" that seems like it could allow this "trick". In Ruby there is also the possibility to load a module dynamically as a language feature, perhaps there is some way to do this in Dart?
Any clues or a simple example will be greatly appreciated.
Thanks in advance!
Ladislav Thon provided this answer on the Dart forum:
I believe it's very safe to say that Dart will never have eval. But it will have other, more structured ways of dynamically generating code (code name mirror builders). There is nothing like that right now, though.
There are two ways of spawning an isolate: spawnFunction, which runs an existing function from the existing code in a new isolate, so nothing you are looking for, and spawnUri, which downloads code from given URI and runs it in new isolate. That is essentially dynamic code loading -- but the dynamically loaded code is isolated from the existing code. It runs in a new isolate, so the only means of communicating with it is via message passing (through ports).
You can run a string as Dart code by first constructing a data URI from it and then passing it into Isolate.spawnUri.
import 'dart:isolate';
void main() async {
final uri = Uri.dataFromString(
'''
void main() {
print("Hellooooooo from the other side!");
}
''',
mimeType: 'application/dart',
);
await Isolate.spawnUri(uri, [], null);
}
Note that you can only do this in JIT mode, which means that the only place you might benefit from it is Dart VM command line apps / package:build scripts. It will not work in Flutter release builds.
To get a result back from it, you can use ports:
import 'dart:isolate';
void main() async {
final name = 'Eval Knievel';
final uri = Uri.dataFromString(
'''
import "dart:isolate";
void main(_, SendPort port) {
port.send("Nice to meet you, $name!");
}
''',
mimeType: 'application/dart',
);
final port = ReceivePort();
await Isolate.spawnUri(uri, [], port.sendPort);
final String response = await port.first;
print(response);
}
I wrote about it on my blog.
Eval(), in Ruby at least, can execute anything from a single statement (like an assignment) to complete involved programs. There is a substantial time penalty for executing many small snippets over most any other form of execution that is possible.
Looking at the problem closer, there are at least three different functions that were at the base of the various schemes where eval might be used. Dart handles at least 2 of these in at least minimal ways.
Dart does not, nor does it look like there is any plan to support "general" script execution.
However, the NoSuchMethod method can be used to effectively implement the dynamic "injection" of variables into your local class environment. It replaces an eval() with a string that would look like this: eval( "String text = 'your first name here';" );
The second function that Dart readily supports now is the invocation of a method, that would look like this: eval( "Map map = SomeClass.some_method()" );
After messing about with this it finally dawned on me that a single simple class can be used to store the information needed to invoke a method, for a class, as a string which seems to have general utility. I can replace a big maintenance prone switch statement that might otherwise be necessary to invoke a series of methods. In Ruby this was almost trivial, however in Dart there are some fairly less than intuitive calls so I wanted to get this "trick" in one place, which fits will with doing ordering and filtering on the strings such as you may need.
Here's the code to "accumulate" as many classes (a whole library?) into a map using reflection such that the class.methodName() can be called with nothing more than a key (as a string).
Note: I used a few "helper methods" to do Map & List functions, you will probably want to replace them with straight Dart. However this code is used and tested only using the functions..
Here's the code:
//The used "Helpers" here..
MAP_add(var map, var key, var value){ if(key != null){map[key] = value;}return(map);}
Object MAP_fetch(var map, var key, [var dflt = null]) {var value = map[key];if (value==null) {value = dflt;}return( value );}
class ClassMethodMapper {
Map _helperMirrorsMap, _methodMap;
void accum_class_map(Object myClass){
InstanceMirror helperMirror = reflect(myClass);
List methodsAr = helperMirror.type.methods.values;
String classNm = myClass.toString().split("'")[1]; ///#FRAGILE
MAP_add(_helperMirrorsMap, classNm, helperMirror);
methodsAr.forEach(( method) {
String key = method.simpleName;
if (key.charCodeAt(0) != 95) { //Ignore private methods
MAP_add(_methodMap, "${classNm}.${key}()", method);
}
});
}
Map invoker( String methodNm ) {
var method = MAP_fetch(_methodMap, methodNm, null);
if (method != null) {
String classNm = methodNm.split('.')[0];
InstanceMirror helperMirror = MAP_fetch(_helperMirrorsMap, classNm);
helperMirror.invoke(method.simpleName, []);
}
}
ClassMethodMapper() {
_methodMap = {};
_helperMirrorsMap = {};
}
}//END_OF_CLASS( ClassMethodMapper );
============
main() {
ClassMethodMapper cMM = new ClassMethodMapper();
cMM.accum_class_map(MyFirstExampleClass);
cMM.accum_class_map(MySecondExampleClass);
//Now you're ready to execute any method (not private as per a special line of code above)
//by simply doing this:
cMM.invoker( MyFirstExampleClass.my_example_method() );
}
Actually there some libraries in pub.dev/packages but has some limitations because are young versions, so that I can recommend you this library expressions to dart and flutter.
A library to parse and evaluate simple expressions.
This library can handle simple expressions, but no blocks of code, control flow statements and so on. It supports a syntax that is common to most programming languages.
There I create an example of code to evaluate arithmetic operations and comparations of data.
import 'package:expressions/expressions.dart';
import 'dart:math';
#override
Widget build(BuildContext context) {
final parsing = FormulaMath();
// Expression example
String condition = "(cos(x)*cos(x)+sin(x)*sin(x)==1) && respuesta_texto == 'si'";
Expression expression = Expression.parse(condition);
var context = {
"x": pi / 5,
"cos": cos,
"sin": sin,
"respuesta_texto" : 'si'
};
// Evaluate expression
final evaluator = const ExpressionEvaluator();
var r = evaluator.eval(expression, context);
print(r);
return Scaffold(
body: Container(
margin: EdgeInsets.only(top: 50.0),
child: Column(
children: [
Text(condition),
Text(r.toString())
],
),
),
);
}
I/flutter (27188): true