use increment inside lambda in java - java

I have a block like this
int i = 0;
shaders.forEach((WrappedShader shader) ->
{
int shader_id = glCreateShader(shader.getShader_type());
glShaderSource(shader_id, shader.getShader_source());
glCompileShader(shader_id);
glAttachShader(shader_program, shader_id);
shader_ids[i++] = shader_id;
});
But how to have increment inside lambda? Currently it asks to set the variable i as final and do not change it.
I know I can rewrite it to for loop but I'd like to use lambda.

Ideally, for functional program you should have pure functions with no side effects. In this case, you have side effects but you could do is
int[] sharedIds = shaders.stream().mapToInt((WrappedShader shader) -> {
int shader_id = glCreateShader(shader.getShader_type());
glShaderSource(shader_id, shader.getShader_source());
glCompileShader(shader_id);
glAttachShader(shader_program, shader_id);
return shared_id;
}).toArray();

Related

How can I change code based on Method Argument?

public static void calculate(List<Person> data, String categoryType) {
for(int i = 0; i < categoryData.size(); i++) {
if(data.get(i).calculateCategoryOne() == firstPlace) {
...
}
}
}
If you see data.get(i).calculateCategoryOne(), the method call is for category one. The problem is that I need to copy-paste the entire code in a if-block for each category to just change this method call data.get(i).calculateCategoryTwo(), data.get(i).calculateCategoryThree(), ... data.get(i).calculateCategoryTen(),
While I can still make the logic work in this way, I feel it is redundant and not a good programming practice. Just to change one line of code, I would have to replicate the same code ten different times which will add nearly 500 lines of code.
So, my question is: Is there a way to dynamically change my method call based on the category type string argument.
I was thinking one possible way is to pass the method call in a string and convert it to a method call itself. For example, let's assume CategoryType string argument is "calculateCategoryOne()". So, data.get(i)."calculateCategoryOne()" would be recognized by the compiler as the method call itself. Is there a way to actually implement this?
I'm open to other ideas as well to reduce redundancy.
I would think using a functional interface would be appropriate here. You want different functionality depending on the categoryType, so passing in the function you want to use, rather than a String representation of it, would accomplish this.
#FunctionalInterface
public interface Calculate {
int calculate(Person data);
}
public static void calculate(List<Person> data, Calculate calculate) {
for(int i = 0; i < categoryData.size(); i++) {
if(calculate.calculate(data.get(i)) == firstPlace) {
...
}
}
}
and the call to the method would define what the calculation would be
calculate(list, p -> {
// calculation done here
});
or if this would happen frequently, you could predefine your categories once and pass those in:
Calculate categoryOne = p -> { ... };
Calculate categoryTwo = p -> { ... };
.
.
calculate(list, categoryOne);

methods with state Groovy / Java

I have a bit of a long winded question. Say I have a method which makes a math calculation and this method needs to keep state (i.e. every time it gets called with parameters its result is affected by its previous results).
int sum
def add(int x, int y) {
sum = sum + x + y
return sum
}
On top of this, its state is dependent on where it was called. (i.e. if I call this method twice from different places the method must only work with its own state). I was thinking about Closures in groovy but closures doesn't keep state and if you store your state in a variable outside of the closure a second call to this method won't have its own state.
Lets also assume for reasons that I won't go into right now I cannot keep this method in a object to keep state. i.e.
class MyObject {
private int sum
MyObject() {}
public int sum(int x, int y) {
sum = sum + x + y
return sum
}
}
I want to avoid doing this
MyObject mObj = new MyObject()
.... some code later
def result = mObj.add(1,2)
instead I just want to have to do this
for (int i = 0; i<5;i++){
def result1 = add(1,2)
}
some code later
for (int i = 0; i<5;i++){
def result2 = add(1,2)
}
In the case above the two 'add' methods should have its own state.
Is there any other tricks in either groovy or java to achieve something like this?
What you are describing here is a closure. The Groovy code there does
already that. If you want put that "global" state into the function, you
could be explicit about it and "build" the add function. E.g.
def add = { ->
def total = 0
return { a, b ->
return total += a + b
}
}()
println(add(1,2))
// -> 3
println(add(1,2))
// -> 6
println(add(1,2))
// -> 9
Above code creates a function, that holds the state for total and
returns a closure, that does the actual add. It captures the local
total. Then this function is called and the result (the closure) is
assigned to add.
edit
As stated in the comments, the expectation is a "magic" boundary that
isolates the state of add over the course of the execution of the
program. Assuming that this question aims for a DSL, users might be
able to know the implicit boundaries. Yet I doubt there is a way with
Groovy (or Java?) to know, that a function is called from inside
a for-loop unless you write your own for.
One way around this would be to create an explicit boundary like this:
def withTotal(c) {
def total = 0
c.add = { total += it }
c.call()
total
}
println withTotal{
add(1)
add(2)
}
// -> 3
println withTotal{
10.times{ add it }
}
// -> 45

Problem binding a boolean property using a lambda [Java - JavaFX] [duplicate]

I want to be able to do something like this:
for(i = 0; i < 10; i++) {
//if any button in the array is pressed, disable it.
button[i].setOnAction( ae -> { button[i].setDisable(true) } );
}
However, I get a error saying "local variables referenced from a lambda expression must be final or effectively final". How might I still do something like the code above (if it is even possible)? If it can't be done, what should be done instead to get a similar result?
As the error message says, local variables referenced from a lambda expression must be final or effectively final ("effectively final" meaning the compiler can make it final for you).
Simple workaround:
for(i = 0; i < 10; i++) {
final int ii = i;
button[i].setOnAction( ae -> { button[ii].setDisable(true) } );
}
Since you are using lambdas, you can benefit also from other features of Java 8, like streams.
For instance, IntStream:
A sequence of primitive int-valued elements supporting sequential and parallel aggregate operations. This is the int primitive specialization of Stream.
can be used to replace the for loop:
IntStream.range(0,10).forEach(i->{...});
so now you have an index that can be used to your purpose:
IntStream.range(0,10)
.forEach(i->button[i].setOnAction(ea->button[i].setDisable(true)));
Also you can generate a stream from an array:
Stream.of(button).forEach(btn->{...});
In this case you won't have an index, so as #shmosel suggests, you can use the source of the event:
Stream.of(button)
.forEach(btn->btn.setOnAction(ea->((Button)ea.getSource()).setDisable(true)));
EDIT
As #James_D suggests, there's no need of downcasting here:
Stream.of(button)
.forEach(btn->btn.setOnAction(ea->btn.setDisable(true)));
In both cases, you can also benefit from parallel operations:
IntStream.range(0,10).parallel()
.forEach(i->button[i].setOnAction(ea->button[i].setDisable(true)));
Stream.of(button).parallel()
.forEach(btn->btn.setOnAction(ea->btn.setDisable(true)));
Use the Event to get the source Node.
for(int i = 0; i < button.length; i++)
{
button[i].setOnAction(event ->{
((Button)event.getSource()).setDisable(true);
});
}
Lambda expressions are effectively like an annonymous method which works on stream. In order to avoid any unsafe operations, Java has made that no external variables which can be modified, can be accessed in a lambda expression.
In order to work around it,
final int index=button[i];
And use index instead of i inside your lambda expression.
You say If the button is pressed, but in your example all the buttons in the list will be disabled. Try to associate a listener to each button rather than just disable it.
For the logic, do you mean something like that :
Arrays.asList(buttons).forEach(
button -> button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
button.setEnabled(false);
}
}));
I Also like Sedrick's answer but you have to add an action listener inside the loop .

Call functions put in array

for my code in Java I need to call functions for some figures inside a number. In fact, if my number is 464, I have to call functions named assert4 and assert6. I hope that you're understanding. But if I'm right, we can't concatenate a string and a variable to have the name of a function and execute it. For example :
for (int i = 0; i < number.length(); i++) {
assert + i + (); // For example executing the function assert4
}
So I can't see how I can do it. Thanks for help !
You can do this with reflection using something like YourClass.class.getMethod(...).invoke(...). (See this question for instance.)
However, this is a bit of a code smell and I encourage you to do something like
Map<Integer, Runnable> methods = new HashMap<>();
methods.put(464, YourClass::assert464);
...
for (int i = 0; i < number.length(); i++) {
methods.get(i).run();
}
If you're on Java 7 or older, the equivalent would be
methods.put(464, new Runnable() { public void run() { assert464(); } });
You can call a method using a String name using the reflection API.
Here's some tutorials on how to get started:
http://docs.oracle.com/javase/tutorial/reflect/
http://www.ibm.com/developerworks/library/j-dyn0603/

java: Is it possible to set a lambda expression for an array of Buttons is a for loop? If so how?

I want to be able to do something like this:
for(i = 0; i < 10; i++) {
//if any button in the array is pressed, disable it.
button[i].setOnAction( ae -> { button[i].setDisable(true) } );
}
However, I get a error saying "local variables referenced from a lambda expression must be final or effectively final". How might I still do something like the code above (if it is even possible)? If it can't be done, what should be done instead to get a similar result?
As the error message says, local variables referenced from a lambda expression must be final or effectively final ("effectively final" meaning the compiler can make it final for you).
Simple workaround:
for(i = 0; i < 10; i++) {
final int ii = i;
button[i].setOnAction( ae -> { button[ii].setDisable(true) } );
}
Since you are using lambdas, you can benefit also from other features of Java 8, like streams.
For instance, IntStream:
A sequence of primitive int-valued elements supporting sequential and parallel aggregate operations. This is the int primitive specialization of Stream.
can be used to replace the for loop:
IntStream.range(0,10).forEach(i->{...});
so now you have an index that can be used to your purpose:
IntStream.range(0,10)
.forEach(i->button[i].setOnAction(ea->button[i].setDisable(true)));
Also you can generate a stream from an array:
Stream.of(button).forEach(btn->{...});
In this case you won't have an index, so as #shmosel suggests, you can use the source of the event:
Stream.of(button)
.forEach(btn->btn.setOnAction(ea->((Button)ea.getSource()).setDisable(true)));
EDIT
As #James_D suggests, there's no need of downcasting here:
Stream.of(button)
.forEach(btn->btn.setOnAction(ea->btn.setDisable(true)));
In both cases, you can also benefit from parallel operations:
IntStream.range(0,10).parallel()
.forEach(i->button[i].setOnAction(ea->button[i].setDisable(true)));
Stream.of(button).parallel()
.forEach(btn->btn.setOnAction(ea->btn.setDisable(true)));
Use the Event to get the source Node.
for(int i = 0; i < button.length; i++)
{
button[i].setOnAction(event ->{
((Button)event.getSource()).setDisable(true);
});
}
Lambda expressions are effectively like an annonymous method which works on stream. In order to avoid any unsafe operations, Java has made that no external variables which can be modified, can be accessed in a lambda expression.
In order to work around it,
final int index=button[i];
And use index instead of i inside your lambda expression.
You say If the button is pressed, but in your example all the buttons in the list will be disabled. Try to associate a listener to each button rather than just disable it.
For the logic, do you mean something like that :
Arrays.asList(buttons).forEach(
button -> button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
button.setEnabled(false);
}
}));
I Also like Sedrick's answer but you have to add an action listener inside the loop .

Categories

Resources