So, this doesn't work, since seatsAvailable is final. How can what I'm trying to accomplish be done using more of a lambda-style-from-the-ground-up way?
final boolean seatsAvailable = false;
theatreSeats.forEach(seat -> {
if (!seatsAvailable) seatsAvailable = seat.isEmpty();
});
It looks like you want seatsAvailable to be true if there is at least one empty seat. Therefore, this should do the trick for you:
final boolean seatsAvailable = theatreSeats.stream().anyMatch(Seat::isEmpty);
(Note: I am assuming that your class is named Seat.)
Related
This question already has answers here:
Variable used in lambda expression should be final or effectively final
(9 answers)
Closed 1 year ago.
I am using Java 8 stream Iteration with a variable that should be used in other classes also. So I have used the below code.
AtomicBoolean bool = new AtomicBoolean(true);
public void testBool(){
list.stream().forEach(c->{
if( c.getName() != null){
bool.set(true);
}
});
}
public void test(){
if(bool.get()){
System.out.println("value is there");
}
}
But I heard like using the Atomic Object will be a performance hit sometimes. Is there any alternate approach to use the variables outside the forEach block with Java 8 usage?
Without this am getting the error as a variable should be a final or effectively final error.
Please help me to resolve this issue.
Thanks in advance.
You could avoid the problem by using the lambda expression to return true or false if there are any names that are not null, and assign the result to your boolean.
Something like this:
boolean hasAnyWithNames = list.stream().anyMatch(c -> c.getName() != null);
The choice "bool" is not a good one for variable name by the way.
Edit:
Replaced Boolean with base type per comment.
Used anyMatch() instead of filter() count per comment
Thanks
The effectively final restriction only applies to local variables.
Since you are setting an instance field, you can simply use:
boolean bool = true; and set it from within the lambda.
If you need to use a local variable, add the final modifier to the declaration.
Regarding the overhead of using AtomicBoolean, keep in mind that streams also have overhead and if you're only using them for iteration you're better off using a for loop instead:
boolean bool = true;
public void testBool(){
for (var c : list) {
if (c.getName() != null) {
bool = true;
break;
}
}
}
Lastly, as #Neela mentioned in a comment, a more efficient use of streams would be with the following code*:
boolean bool = list.stream().anyMatch(c -> c.getName() != null);
*Note, the original code has an error that results in bool always being true and this is avoided by not presetting true and directly putting the result of anyMatch.
Using the following code, I can set a couple variables to my matches. I want to do the same thing, but populate a map of all instances of these results. I'm struggling and could use help.
val (dice, level) = Regex("""([0-9]*d[0-9]*) at ([0-9]*)""").matchEntire(text)?.destructured!!
This code works for one instance, none of my attempts at matching multiple are working.
Your solution is short and readable. Here are a few options the one you use is largely a matter of preference. You can get a Map directly by using the associate method as follows.
val diceLevels = levelMatches.associate { matched ->
val (diceTwo,levelTwo) = matched.destructured
(levelTwo to diceTwo)
}
Note: This creates an immutable map. If you want a MutableMap, you can use associateTo.
If you want to be concise, you can simplify out the destructuring to local variables and index the groups directly.
val diceLevels = levelMatches.associate {
(it.groupValues[2] to it.groupValues[1])
}
Or, using let, you can also avoid needing to declare levelMatches as a local variable if it isn't used elsewhere --
val diceLevels = Regex("([0-9]+d[0-9]+) at ([0-9]+)")
.findAll(text)
.let { levelMatches ->
levelMatches.associate {
(it.groupValues[2] to it.groupValues[1])
}
}
I realized this was no where near as complicated as I was making it. Here was my solution. Is there something more elegant?
val levelMatches = Regex("([0-9]+d[0-9]+) at ([0-9]+)").findAll(text)
levelMatches.forEach { matched ->
val (diceTwo,levelTwo) = matched.destructured
diceLevels[levelTwo] = diceTwo
}
Say I have a currency rates loader returning isLoaded=true result only when all the rates are loaded successfully:
//List<String> listFrom = Stream.of("EUR", "RUB").collect(toList());
//List<String> listTo = Stream.of("EUR", "CNY").collect(toList());
boolean isLoaded = true;
final FixerDataProvider httpProvider = new FixerDataProvider(maxAttempts);
final List<CurrencyRatePair> data =
listFrom.stream()
.flatMap(from -> {
final List<CurrencyRatePair> result = httpProvider.findRatesBetweenCurrencies(from, listTo);
if (Objects.isNull(result) || result.size() == 0) {
isLoaded = false; //!!!Not working as ineffectively final!!!
}
return result.stream();
}).collect(Collectors.toList());
if (!isLoaded) {
return false;
}
// do smth with loaded data
return true;
Assignment isLoaded = false; inside lambda function is not allowed when isLoaded variable is not final or effectively final.
Which is the most elegant solution to set/drop boolean flag inside lambda expressions?
What do you think about AtomicBoolean and set(false) method as a possible approach?
You may be better off with an old-style loop, as others have suggested. It does feel like a bit of a programming faux pas to write lambdas with side-effects, but you're likely to find an equal number of developers who think it's fine too.
As for getting this particular lambda-with-side effects working, making isLoaded into an AtomicBoolean is probably your best bet. You could achieve the same effect by making isLoaded a boolean[] of size 1, but that seems less elegant than going with AtomicBoolean to me.
But seriously, try using an old-school loop instead too and see which one you like better.
If you use parallel stream, you must use AtomicBoolean. Because boolean[1] may not be safe in parallel scenario.
The java.util.stream javadoc states that
Side-effects in behavioral parameters to stream operations are, in general, discouraged, as they can often lead to unwitting violations of the statelessness requirement, as well as other thread-safety hazards.
That said, if you want to do it anyway, the solution you have identified with an AtomicBoolean will do the trick just fine.
Variables used within anonymous inner classes and lambda expression have to be effectively final.
You can use AtomicReference for your case, here is a similar snippet from ConditionEvaluationListenerJava8Test
public void expectedMatchMessageForAssertionConditionsWhenUsingLambdasWithoutAlias() {
final AtomicReference<String> lastMatchMessage = new AtomicReference<>();
CountDown countDown = new CountDown(10);
with()
.conditionEvaluationListener(condition -> {
try {
countDown.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
lastMatchMessage.set(condition.getDescription());
})
.until(() -> assertEquals(5, (int) countDown.get()));
String expectedMatchMessage = String.format("%s reached its end value", CountDown.class.getName());
assertThat(lastMatchMessage.get(), allOf(startsWith("Condition defined as a lambda expression"), endsWith(expectedMatchMessage)));
}
Cheers !
If I right understand you will get isLoaded=false only in case if all off result lists will be empty (If result list is null you will get NPE in the next line so there is no any reason to do null check in this way). In this case your data list also will be empty and you don't need any boolean flags, just check if data.isEmpty() and return false if true.
for a piece of homework, I have to set a variable. The set method given to me, converts that into "Optional". However, I have to store this variable in an ArrayList which doesn't allow Optional variables.How can I convert the variable so it is no longer Optional?
The set method:
public void setParentVertex(IVertex<T> parentVertex)
{
if(parentVertex == null)
this.parentVertex = Optional.empty();
else
this.parentVertex = Optional.of(parentVertex);
}
Where I'm trying to use it:
ArrayList<IVertex<T>> path = new ArrayList<IVertex<T>>();
IVertex<T> parent = current.getLabel().getParentVertex();
path.add(parent);
The error I keep receiving is: "Error: incompatible types: Optional> cannot be converted to IVertex" due to the line where I declare the variable "parent".
Thank you.
Here is the correct version
List<IVertex<T>> path = new ArrayList<IVertex<T>>();
current.getLabel().getParentVertex().ifPresent(path::add)
Also it would be good to rewrite setParentVertex function:
public void setParentVertex(IVertex<T> parentVertex) {
this.parentVertex = Optional.ofNullable(parentVertex);
}
I think you don't have to add it to your list, if there is no value. So just do
if(nameOfOptional.isPresent()){
list.add(nameOfOptional.get());
}
First, add a check to find the value is present or not (by calling isPresent()) and then if the value is present then add to your ArrayList path object as shown below:
ArrayList<IVertex<T>> path = new ArrayList<>();
Optional<IVertex<T>> parent = current.getLabel().getParentVertex();
if(parent.isPresent()) {
path.add(parent.get());
}
or the shorter form is shown below which uses ifPresent method:
ArrayList<IVertex<T>> path = new ArrayList<>();
Optional<IVertex<T>> parent = current.getLabel().getParentVertex();
parent.ifPresent(path::add);
Also, I suggest you have a look at the Optional API methods here.
As a side note, I recommend you to use diamond <> operator while declaring generic types (like shown above i.e., new ArrayList<>()) , so that your code will be less verbose.
Situation: I'm working on legacy code and trying to improve readability. The following example should visualize the intent:
private static final String CONSTANT_1 = "anyValue";
private static final String CONSTANT_2 = "anyValue";
private static final String CONSTANT_3 = "anyValue";
private static final String CONSTANT_4 = "anyValue";
private static final String CONSTANT_5 = "anyValue";
private final SomeType someField = new SomeType();
private void contentOfSomeMethods(){
someMethod(someField, CONSTANT_1, true);
someMethod(someField, CONSTANT_2, true);
someMethod(someField, CONSTANT_3, true);
someMethod(someField, CONSTANT_4, false);
someMethod(someField, CONSTANT_5, false);
}
private void someMethod(SomeType type, String value, boolean someFlag) { }
Imagine, there are about 50 calls of someMethod using about 50 constants. I want to do safe automatical refactorings on that code so that the contentOfSomeMethods method changes to
private void contentOfSomeMethods(){
doItWith(CONSTANT_1);
doItWith(CONSTANT_2);
doItWith(CONSTANT_3);
doItNotWith(CONSTANT_4);
doItNotWith(CONSTANT_5);
}
and two additional methods are generated:
private void doItWith(String value) {
someMethod(someField, value, true);
}
private void doItNotWith(String value) {
someMethod(someField, value, false);
}
The naive way is to extract all constants in contentOfSomeMethods inside local variables and use then the extract method refactoring to create the desired methods. And afterwards to inline back the local variables. But this solution doesn't scale up.
Another way is to use search and replace with regular expressions, but this is not a safe refactoring, so I could break the code without noticing it.
Do you have any better suggestions? Do you know some plugins for Eclipse that allow that?
I don't know of any utility that would do this directly.
I think using a regular expression is the only to go. First, you will need to create the two target methods doItWith and doItNotWith. Then, you can highlight the contents of the method contentOfSomeMethods, hit Ctrl+F, and use the following regular expressions:
Find: someMethod\(someField, (\w*), true\);
Replace with: doItWith(\1);
and then
Find: someMethod\(someField, (\w*), false\);
Replace with: doItNotWith(\1);
Be sure to check "Regular Expressions" and "Selected lines". Here's a picture of it:
The regular expressions match the constant that is used inside the function call with (\w*) and then it is used during the replacement with \1. Using this regular expression only on the selected lines minimizes the chance of breaking unrelated code.
Do it with a regular expression and verify it.
I'm assuming that each call to someMethod spans only one line. If not this method is still useful but slower.
Copy the original file.
Use ctrl+alt+h to show the Callers of someMethod and get a count of them.
Do regex search and replaces restricted to the proper area :
Find : someMethod(someField,([ ]*CONSTANT_[0-9]+)[ ]*,[ ]*true[ ]*)[ ]*;
Replace : doItWith("$1");
Find : someMethod(someField,([ ]*CONSTANT_[0-9]+)[ ]*,[ ]*false[ ]*)[ ]*;
Replace : doItNotWith("$1");
Make a diff of the original file and the new file showing only the lines of the original file which have changed.
diff --changed-group-format='%<' --unchanged-group-format='' original.java refactored.java | wc
You should get the same number of lines as you got in the callers of someMethod.
If the calls to someMethod are multiline, or if you want greater verification, just drop | wc to see the lines which were modified in the original file to ensure that only the correct lines have been modified.
Alas I know nothing in Eclipse that allows to do this today.
This is something I would like to achieve one day in AutoRefactor: https://github.com/JnRouvignac/AutoRefactor/issues/8
However the road to get there is quite long.
The only ways I know today are to extract local variables then extract method (as you suggested) or use regexes (as somebody else suggested).