Averaging across multiple fields with IntSummaryStatistics - java

I'm trying to use Java 8 streams to create a single CarData object, which consists of an average of all the CarData fields in the list coming from getCars;
CarData = new CarData();
CarData.getBodyWeight returns Integer
CarData.getShellWeight returns Integer
List<CarData> carData = carResults.getCars();
IntSummaryStatistics averageBodyWeight = carData.stream()
.mapToInt((x) -> x.getBodyWeight())
.summaryStatistics();
averageBodyWeight.getAverage();
IntSummaryStatistics averageShellWeight = carData.stream()
.mapToInt((x) -> x.getShellWeight())
.summaryStatistics();
getShellWeight.getAverage();
I don't want to have to put each of these back together in my final returned result.
Visually, this is my list
getCars() : [
{CarData: { getBodyWeight=10, getShellWeight=3 } }
{CarData: { getBodyWeight=6, getShellWeight=5 } }
{CarData: { getBodyWeight=8, getShellWeight=19 } }
]
and the output I'm trying to achieve is a single object that has the average of each of the fields I specify. not sure If I need to use Collectors.averagingInt or some combo of IntSummaryStatistics to achieve this. Easy to do across one field for either of these techniques, just not sure what I'm missing when using multiple integer fields.
{CarData: { getBodyWeight=8, getShellWeight=9 } }

Starting with JDK 12, you can use the following solution:
CarData average = carData.stream().collect(Collectors.teeing(
Collectors.averagingInt(CarData::getBodyWeight),
Collectors.averagingInt(CarData::getShellWeight),
(avgBody, avgShell) -> new CarData(avgBody.intValue(), avgShell.intValue())));
For older Java versions, you can do either, add the teeing implementation of this answer to your code base and use it exactly as above or create a custom collector tailored to your task, as shown in Andreas’ answer.
Or consider that streaming twice over a List in memory is not necessarily worse than doing two operations in one stream, both, readability- and performance-wise.
Note that calling intValue() on Double objects has the same behavior as the (int) casts in Andreas’ answer. So in either case, you have to adjust the code if other rounding behavior is intended.
Or you consider using a different result object, capable of holding two floating point values for the averages.

You need to write your own Collector, something like this:
class CarDataAverage {
public static Collector<CarData, CarDataAverage, Optional<CarData>> get() {
return Collector.of(CarDataAverage::new, CarDataAverage::add,
CarDataAverage::combine,CarDataAverage::finish);
}
private long sumBodyWeight;
private long sumShellWeight;
private int count;
private void add(CarData carData) {
this.sumBodyWeight += carData.getBodyWeight();
this.sumShellWeight += carData.getShellWeight();
this.count++;
}
private CarDataAverage combine(CarDataAverage that) {
this.sumBodyWeight += that.sumBodyWeight;
this.sumShellWeight += that.sumShellWeight;
this.count += that.count;
return this;
}
private Optional<CarData> finish() {
if (this.count == 0)
return Optional.empty();
// adjust as needed if averages should be rounded
return Optional.of(new CarData((int) (this.sumBodyWeight / this.count),
(int) (this.sumShellWeight / this.count)));
}
}
You then use it like this:
List<CarData> list = ...
Optional<CarData> averageCarData = list.stream().collect(CarDataAverage.get());

Related

How we I achieve add(4)(10)(20)(3)(1).total using Java Function?

I am learning usage of,
java.util.function.Function
I wrote a code which uses java Function to add 4 to itself,
the code is as follows,
public class Test01 {
public static void main(String[] args) {
Function<Integer,Integer> addFunction = new Function<Integer,Integer>() {
private int total = 0;
public Integer apply(Integer value) {
this.total += value;
return this.total;
}
};
int finalTotal = addFunction.andThen(addFunction)
.andThen(addFunction)
.andThen(addFunction)
.apply(4);
System.out.println(finalTotal);
}
}
When I run the above code the output which I get is
32
How can I achieve something which I did in javaScript which is as follows,
var fn19 = function(){
var addNum = function(num){
var fn = function(num2){
fn.sum += num2;
return fn;
};
fn.sum = num;
return fn;
};
print("addNum(3)(4)(3)(10) ==> "+addNum(3)(4)(3)(10).sum);
};
fn19();
The output of the above code is
addNum(3)(4)(3)(10) ==> 20
Can I have the same kind of java function call where I can pass as many number arguments and the addFunction will add those many numbers.
An example, as close as possible to your JavaScript code, would be
class QuestionableConstruct {
int sum;
QuestionableConstruct add(int num2) {
sum += num2;
return this;
}
}
Runnable fn19 = () -> {
IntFunction<QuestionableConstruct> addNum = num -> {
QuestionableConstruct fn = new QuestionableConstruct();
fn.sum = num;
return fn;
};
System.out.println("addNum(3)(4)(3)(10)==> "+addNum.apply(3).add(4).add(3).add(10).sum);
};
fn19.run();
A more Java like solution would be
interface Add {
int sum();
default Add add(int num) {
int sum = sum() + num;
return () -> sum;
}
static Add num(int num) {
return () -> num;
}
}
usable as
System.out.println("addNum(3)(4)(3)(10) ==> "+Add.num(3).add(4).add(3).add(10).sum());
Unlike the JavaScript construct, this uses real immutable functions. Consider
Add a = Add.num(1).add(2).add(3);
System.out.println("1+2+3+4+5 = "+a.add(4).add(5).sum());
System.out.println("1+2+3+10+20 = "+a.add(10).add(20).sum());
which works smoothly without interference.
But of course, if you just want to sum a variable number of items, use
System.out.println("addNum(3)(4)(3)(10) ==> "+IntStream.of(3, 4, 3, 10).sum());
or if you want a mutable accumulator, use
System.out.println("addNum(3)(4)(3)(10) ==> "+
IntStream.builder().add(3).add(4).add(3).add(10).build().sum());
which allows to keep the builder and pass it around.
You can't exactly do that in Java, what you are looking for is reducing a stream of values.
In other words: the "real" functional solution here isn't to call one method with multiple arguments. You rather have the values in some list, and then you define the function that "accumulates" over the content of that list, by applying a function on the elements.
See here for some examples.
The technique you're describing in the JavaScript world is taking advantage of a closure.
This is a nice side-effect of functions in JavaScript being first-class citizens. It's a way of associating functions with data in the enclosing scope and then being able to pass this association around without losing inner context. The most common/simple use of which is caching(its formal name being memoisation).
You would need functions(methods) in Java to be first class, but doing so would be redundant as classes by design are an entity which associates data and methods, making the whole concept of a closure in this context redundant.

Java - How to compare Guava Ranges?

I decided to create a Map to store metric names and the Ranges representing live periods for each metric. At first I used a TreeRangeMap to store the Ranges but since each Metric contains a single Range I switched to Ranges as shown below.
My goal is to keep the latest time range in the DEFAULT_METRICS_MAP when I receive a Range for the metric from external API.
When I had a TreeRangeMap representing Ranges, comparing them was easy. I added new metric to the TreeRangeMap and then got the max range like this:
private static Optional<Range<Long>> maxRange(TreeRangeSet<Long> rangeSet) {
Set<Range<Long>> ranges = rangeSet.asRanges();
return ranges.stream().max(Comparator.comparing(Range::upperEndpoint));
}
What would be the correct way to compare Ranges when they are not wrapped into a TreeRangeMap?
public static final Map<String, Range<Long>> DEFAULT_METRICS_MAP;
static {
Map<String, Range<Long>> theMap = new HashMap<>();
theMap.put("Metric1", Range.closed(Long.MIN_VALUE, Long.MAX_VALUE));
theMap.put("Metric2", Range.closed(10L, 20L));
theMap.put("Metric3", Range.closed(30L, 50L));
METRICS_MAP = Collections.unmodifiableMap(theMap);
}
First of all it was a correct decission to avoid using TreeRangeMap/TreeRangeSet in this particular case. As I understand (correct me if I'm wrong), you don't need to keep all the ranges for all the metrics. What you need is the latest range for each metric at every moment in time.
Ideally you would like to have a very fast method of retriving, like:
Range<Long> range = getRange(metric);
The most efficient way is to compare Range objects on receiving them:
public void setRange(String metric, Range<Long> newRange) {
Range<Long> oldRange = metricRanges.get(metric);
if (comparator.compare(newRange, oldRange) > 0) {
metricRanges.put(metric, newRange);
}
}
Here is the full example:
// Better keep this map encapsulated
private final Map<String, Range<Long>> metricRanges = new HashMap<>();
private final Comparator<Range<Long>> comparator =
Comparator.nullsFirst(Comparator.comparing(Range::upperEndpoint));
static {
// Fill in your map with default ranges
}
public void setRange(String metric, Range<Long> newRange) {
Range<Long> oldRange = metricRanges.get(metric);
if (comparator.compare(newRange, oldRange) > 0) {
metricRanges.put(metric, newRange);
}
}
public Range<Long> getRange(String metric) {
return metricRanges.get(metric);
}
If you still need Optional:
public Optional<Range<Long>> getRange(String metric) {
return Optional.of(metricRanges.get(metric));
}

Can we combine two methods that differ largely based on type?

I have two similar, but of different types, blocks of code in Java:
private Integer readInteger() {
Integer value = null;
while (value == null) {
if (scanner.hasNextInt()) {
value = scanner.nextInt();
} else {
scanner.next();
}
}
return value;
}
private Double readDouble() {
Double value = null;
while (value == null) {
if (scanner.hasNextDouble()) {
value = scanner.nextDouble();
} else {
scanner.next();
}
}
return value;
}
Is it possible to make just one method which would work for both of them?
I'd say, use a generic method, combined with the functional interfaces introduced in Java 8.
The method read now becomes a higher order function.
private <T> T read(Predicate<Scanner> hasVal, Function<Scanner, T> nextVal) {
T value = null;
while (value == null) {
if (hasVal.test(scanner)) {
value = nextVal.apply(scanner);
} else {
scanner.next();
}
}
return value;
}
Calling code becomes:
read(Scanner::hasNextInt, Scanner::nextInt);
read(Scanner::hasNextDouble, Scanner::nextDouble);
read(Scanner::hasNextFloat, Scanner::nextFloat);
// ...
So the readInteger() method can be adapted as follows:
private Integer readInteger() {
return read(Scanner::hasNextInt, Scanner::nextInt);
}
You could have something with three methods:
One which says if there is a value of the right type
Another which gets the value of the right type.
Another which discards whatever token you have.
For example:
interface Frobnitz<T> {
boolean has();
T get();
void discard();
}
You can pass this into your method:
private <T> T read(Frobnitz<? extends T> frob) {
T value = null;
while (value == null) {
if (frob.has()) {
value = frob.get();
} else {
frob.discard();
}
}
return value;
}
And then just implement Frobnitz for your Double and Integer cases.
To be honest, I'm not sure this gets you very much, especially if you've only got two cases; I'd be inclined just to suck up the small amount of duplication.
A lot of people have answered that you can use generics, but you can also simply remove the readInteger method, and only use the readDouble, as integers can be converted to doubles without data loss.
This is about code duplication.
The general approach is to turn similar code (you have) into equal code that can be extracted to a common parameterized method.
In your case what make the two code snipped differ is the access to methods of Scanner. You have to encapsulate them somehow. I'd suggest to do this with Java8 Functional interfaces like this:
#FunctionalInterface
interface ScannerNext{
boolean hasNext(Scanner scanner);
}
#FunctionalInterface
interface ScannerValue{
Number getNext(Scanner scanner);
}
Then replace the actual invocation of methods in scanner with the functional interface:
private Integer readInteger() {
ScannerNext scannerNext = (sc)->sc.hasNextInt();
ScannerValue scannerValue = (sc)-> sc.nextInt();
Integer value = null;
while (value == null) {
if (scannerNext.hasNext(scanner)) {
value = scannerValue.getNext(scanner);
} else {
scanner.next();
}
}
return value;
}
There is one more problem that the type of the value variable differs. So we replace it with its common supertype:
private Integer readInteger() {
ScannerNext scannerNext = (sc)->sc.hasNextInt();
ScannerValue scannerValue = (sc)-> sc.nextInt();
Number value = null;
while (value == null) {
if (scannerNext.hasNext(scanner)) {
value = scannerValue.getNext(scanner);
} else {
scanner.next();
}
}
return (Integer)value;
}
Now you have to places with a big equal section. You can select one of those sections starting with Number value = null; ending with the } before return ... and invoke your IDEs automated refactoring extract method:
private Number readNumber(ScannerNext scannerNext, ScannerValue scannerValue) {
Number value = null;
while (value == null) {
if (scannerNext.hasNext(scanner)) {
value = scannerValue.getNext(scanner);
} else {
scanner.next();
}
}
return value;
}
private Integer readInteger() {
return (Integer) readNumber( (sc)->sc.hasNextInt(), (sc)-> sc.nextInt());
}
private Double readDouble() {
return (Double) readNumber( (sc)->sc.hasNextDouble(), (sc)-> sc.nextDouble());
}
Comments argue against the use of custom interfaces against predefined interfaces from the JVM.
But my point in this answer was how to turn similar code into equal code so that it can be extracted to a single method rather that giving a concrete solution for this random problem.
Not an ideal solution but it still achieves the necessary removal of duplicate code and has the added benefit of not requiring Java-8.
// This could be done better.
static final Scanner scanner = new Scanner(System.in);
enum Read{
Int {
#Override
boolean hasNext() {
return scanner.hasNextInt();
}
#Override
<T> T next() {
return (T)Integer.valueOf(scanner.nextInt());
}
},
Dbl{
#Override
boolean hasNext() {
return scanner.hasNextDouble();
}
#Override
<T> T next() {
return (T)Double.valueOf(scanner.nextDouble());
}
};
abstract boolean hasNext();
abstract <T> T next();
// All share this method.
public <T> T read() {
T v = null;
while (v == null) {
if ( hasNext() ) {
v = next();
} else {
scanner.next();
}
}
return v;
}
}
public void test(String[] args) {
Integer i = Read.Int.read();
Double d = Read.Dbl.read();
}
There are some minor issues with this such as the casting but it should be a reasonable option.
A totally different approach from my other answer (and the other answers): don't use generics, but instead just write the methods more concisely, so you don't really notice the duplication.
TL;DR: rewrite the methods as
while (!scanner.hasNextX()) scanner.next();
return scanner.nextX();
The overall goal - write it as a single method - is only possible if you accept some amount of additional cruft.
Java method signatures do not take into account the return type, so it's not possible to have a next() method return an Integer in one context, and Double in another (short of returning a common supertype).
As such, you have to have something at the call sites to distinguish these cases:
You might consider passing something like Integer.class or Double.class. This does have the advantage that you can use generics to know that the returned value matches that type. But callers could pass in something else: how would you handle Long.class, or String.class? Either you need to handle everything, or you fail at runtime (not a good option). Even with a tighter bound (e.g. Class<? extends Number>), you still need to handle more than Integer and Double.
(Not to mention that writing Integer.class and Double.class everywhere is really verbose)
You might consider doing something like #Ward's answer (which I do like, BTW: if you're going to do it with generics, do it like that), and pass in functional objects which are able to deal with the type of interest, as well as providing the type information to indicate the return type.
But, again, you've got to pass these functional objects in at each call site, which is really verbose.
In taking either of these approaches, you can add helper methods which pass the appropriate parameters to the "generic" read method. But this feels like a backwards step: instead of reducing the number of methods to 1, it's increased to 3.
Additionally, you now have to distinguish these helper methods somehow at the call sites, in order to be able to call the appropriate one:
You could have overloads with a parameter of value type, rather than class type, e.g.
Double read(Double d)
Integer read(Integer d)
and then call like Double d = read(0.0); Integer i = read(0);. But anybody reading this code is going to be left wondering what that magic number in the code is - is there any significance to the 0?
Or, easier, just call the two overloads something different:
Double readDouble()
Integer readInteger()
This is nice and easy: whilst it's slightly more verbose than read(0.0), it's readable; and it's way more concise that read(Double.class).
So, this has got us back to the method signatures in OP's code. But this hopefully justifies why you still want to keep those two methods. Now to address the contents of the methods:
Because Scanner.nextX() doesn't return null values, the method can be rewritten as:
while (!scanner.hasNextX()) scanner.next();
return scanner.nextX();
So, it's really easy to duplicate this for the two cases:
private Integer readInteger() {
while (!scanner.hasNextInt()) scanner.next();
return scanner.nextInt();
}
private Double readDouble() {
while (!scanner.hasNextDouble()) scanner.next();
return scanner.nextDouble();
}
If you want, you could pull out a method dropUntil(Predicate<Scanner>) method to avoid duplicating the loop, but I'm not convinced it really saves you that much.
A single (near-)duplicated line is way less burdensome in your code than all those generics and functional parameters. It's just plain old code, which happens to be more concise (and, likely, more efficient) than "new" ways to write it.
The other advantage of this approach is that you don't have to use boxed types - you can make the methods return int and double, and not have to pay the boxing tax unless you actually need it.
This may not be of advantage to OP, since the original methods do return the boxed type; I don't know if this is genuinely desired, or merely an artefact of the way the loop was written. However, it is useful in general not to create those objects unless you really need them.
Reflection is an alternative if you don't care about performance.
private <T> T read(String type) throws Exception {
Method readNext = Scanner.class.getMethod("next" + type);
Method hasNext = Scanner.class.getMethod("hasNext" + type);
T value = null;
while (value == null) {
if ((Boolean) hasNext.invoke(scanner)) {
value = (T) readNext.invoke(scanner);
} else {
scanner.next();
}
}
return value;
}
Then you call
Integer i = read("Int");

Finite generated Stream in Java - how to create one?

In Java, one can easily generate an infinite stream with Stream.generate(supplier). However, I would need to generate a stream that will eventually finish.
Imagine, for example, I want a stream of all files in a directory. The number of files can be huge, therefore I can not gather all the data upfront and create a stream from them (via collection.stream()). I need to generate the sequence piece by piece. But the stream will obviously finish at some point, and terminal operators like (collect() or findAny()) need to work on it, so Stream.generate(supplier) is not suitable here.
Is there any reasonable easy way to do this in Java, without implementing the entire Stream interface on my own?
I can think of a simple hack - doing it with infinite Stream.generate(supplier), and providing null or throwing an exception when all the actual values are taken. But it would break the standard stream operators, I could use it only with my own operators that are aware of this behaviour.
CLARIFICATION
People in the comments are proposing me takeWhile() operator. This is not what I meant. How to phrase the question better... I am not asking how to filter (or limit) an existing stream, I am asking how to create (generate) the stream - dynamically, without loading all the elements upfront, but the stream would have a finite size (unknown in advance).
SOLUTION
The code I was looking for is
Iterator it = myCustomIteratorThatGeneratesTheSequence();
StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false);
I just looked into java.nio.file.Files, how the list(path) method is implemented.
Is there any reasonable easy way to do this in Java, without implementing the entire Stream interface on my own?
A simple .limit() guarantees that it will terminate. But that's not always powerful enough.
After the Stream factory methods the simplest approach for creating customs stream sources without reimplementing the stream processing pipeline is subclassing java.util.Spliterators.AbstractSpliterator<T> and passing it to java.util.stream.StreamSupport.stream(Supplier<? extends Spliterator<T>>, int, boolean)
If you're intending to use parallel streams note that AbstractSpliterator only yields suboptimal splitting. If you have more control over your source fully implementing the Spliterator interface can better.
For example, the following snippet would create a Stream providing an infinite sequence 1,2,3...
in that particular example you could use IntStream.range()
But the stream will obviously finish at some point, and terminal operators like (collect() or findAny()) need to work on it.
short-circuiting operations like findAny() can actually finish on an infinite stream, as long as there is any element that matches.
Java 9 introduces Stream.iterate to generate finite streams for some simple cases.
Kotlin code to create Stream of JsonNode from InputStream
private fun InputStream.toJsonNodeStream(): Stream<JsonNode> {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(this.toJsonNodeIterator(), Spliterator.ORDERED),
false
)
}
private fun InputStream.toJsonNodeIterator(): Iterator<JsonNode> {
val jsonParser = objectMapper.factory.createParser(this)
return object: Iterator<JsonNode> {
override fun hasNext(): Boolean {
var token = jsonParser.nextToken()
while (token != null) {
if (token == JsonToken.START_OBJECT) {
return true
}
token = jsonParser.nextToken()
}
return false
}
override fun next(): JsonNode {
return jsonParser.readValueAsTree()
}
}
}
Here is a stream which is custom and finite :
package org.tom.stream;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class GoldenStreams {
private static final String IDENTITY = "";
public static void main(String[] args) {
Stream<String> stream = java.util.stream.StreamSupport.stream(new Spliterator<String>() {
private static final int LIMIT = 25;
private int integer = Integer.MAX_VALUE;
{
integer = 0;
}
#Override
public int characteristics() {
return Spliterator.DISTINCT;
}
#Override
public long estimateSize() {
return LIMIT-integer;
}
#Override
public boolean tryAdvance(Consumer<? super String> arg0) {
arg0.accept(IDENTITY+integer++);
return integer < 25;
}
#Override
public Spliterator<String> trySplit() {
System.out.println("trySplit");
return null;
}}, false);
List<String> peeks = new ArrayList<String>();
List<String> reds = new ArrayList<String>();
stream.peek(data->{
peeks.add(data);
}).filter(data-> {
return Integer.parseInt(data)%2>0;
}).peek(data ->{
System.out.println("peekDeux:"+data);
}).reduce(IDENTITY,(accumulation,input)->{
reds.add(input);
String concat = accumulation + ( accumulation.isEmpty() ? IDENTITY : ":") + input;
System.out.println("reduce:"+concat);
return concat;
});
System.out.println("Peeks:"+peeks.toString());
System.out.println("Reduction:"+reds.toString());
}
}
While the author has discarded the takeWhile option, I find it adequate for certain use cases and worth an explanation.
The method takeWhile can be used on any stream and will terminate the stream when the predicate provided to the method returns false. The object which results in a false is not appended to the stream; only the objects which resulted in true are passed downstream.
So one method for generating a finite stream could be to use the Stream.generate method and return a value which signals the end of the stream by being evaluated to false by the predicate provided to takeWhile.
Here's an example, generating all the permutations of an array :
public static Stream<int[]> permutations(int[] original) {
int dim = original.length;
var permutation = original.clone();
int[] controller = new int[dim];
var low = new AtomicInteger(0);
var up = new AtomicInteger(1);
var permutationsStream = Stream.generate(() -> {
while (up.get() < dim) {
if (controller[up.get()] < up.get()) {
low.set(up.get() % 2 * controller[up.get()]);
var tmp = permutation[low.get()];
permutation[low.get()] = permutation[up.get()];
permutation[up.get()] = tmp;
controller[up.get()]++;
up.set(1);
return permutation.clone();
} else {
controller[up.get()] = 0;
up.incrementAndGet();
}
}
return null;
}).takeWhile(Objects::nonNull);
return Stream.concat(
Stream.ofNullable(original.clone()),
permutationsStream
);
}
In this example, I used the null value to signal the end of the stream.
The caller of the method won't receive the null value !
OP could use a similar strategy, and combine it with a visitor pattern.
If it's a flat directory, OP would be better off using Stream.iterate with the seed being the index of the file to yield and Stream.limit on the number of files (which can be known without browsing the directory).

Modifying local variable from inside lambda

Modifying a local variable in forEach gives a compile error:
Normal
int ordinal = 0;
for (Example s : list) {
s.setOrdinal(ordinal);
ordinal++;
}
With Lambda
int ordinal = 0;
list.forEach(s -> {
s.setOrdinal(ordinal);
ordinal++;
});
Any idea how to resolve this?
Use a wrapper
Any kind of wrapper is good.
With Java 10+, use this construct as it's very easy to setup:
var wrapper = new Object(){ int ordinal = 0; };
list.forEach(s -> {
s.setOrdinal(wrapper.ordinal++);
});
With Java 8+, use either an AtomicInteger:
AtomicInteger ordinal = new AtomicInteger(0);
list.forEach(s -> {
s.setOrdinal(ordinal.getAndIncrement());
});
... or an array:
int[] ordinal = { 0 };
list.forEach(s -> {
s.setOrdinal(ordinal[0]++);
});
Note: be very careful if you use a parallel stream. You might not end up with the expected result. Other solutions like Stuart's might be more adapted for those cases.
For types other than int
Of course, this is still valid for types other than int.
For instance, with Java 10+:
var wrapper = new Object(){ String value = ""; };
list.forEach(s->{
wrapper.value += "blah";
});
Or if you're stuck with Java 8 or 9, use the same kind of construct as we did above, but with an AtomicReference...
AtomicReference<String> value = new AtomicReference<>("");
list.forEach(s -> {
value.set(value.get() + s);
});
... or an array:
String[] value = { "" };
list.forEach(s-> {
value[0] += s;
});
This is fairly close to an XY problem. That is, the question being asked is essentially how to mutate a captured local variable from a lambda. But the actual task at hand is how to number the elements of a list.
In my experience, upward of 80% of the time there is a question of how to mutate a captured local from within a lambda, there's a better way to proceed. Usually this involves reduction, but in this case the technique of running a stream over the list indexes applies well:
IntStream.range(0, list.size())
.forEach(i -> list.get(i).setOrdinal(i));
If you only need to pass the value from the outside into the lambda, and not get it out, you can do it with a regular anonymous class instead of a lambda:
list.forEach(new Consumer<Example>() {
int ordinal = 0;
public void accept(Example s) {
s.setOrdinal(ordinal);
ordinal++;
}
});
As the used variables from outside the lamda have to be (implicitly) final, you have to use something like AtomicInteger or write your own data structure.
See
https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#accessing-local-variables.
An alternative to AtomicInteger is to use an array (or any other object able to store a value):
final int ordinal[] = new int[] { 0 };
list.forEach ( s -> s.setOrdinal ( ordinal[ 0 ]++ ) );
But see the Stuart's answer: there might be a better way to deal with your case.
Yes, you can modify local variables from inside lambdas (in the way shown by the other answers), but you should not do it. Lambdas have been made for functional style of programming and this means: No side effects. What you want to do is considered bad style. It is also dangerous in case of parallel streams.
You should either find a solution without side effects or use a traditional for loop.
If you are on Java 10, you can use var for that:
var ordinal = new Object() { int value; };
list.forEach(s -> {
s.setOrdinal(ordinal.value);
ordinal.value++;
});
You can wrap it up to workaround the compiler but please remember that side effects in lambdas are discouraged.
To quote the javadoc
Side-effects in behavioral parameters to stream operations are, in general, discouraged, as they can often lead to unwitting violations of the statelessness requirement
A small number of stream operations, such as forEach() and peek(), can operate only via side-effects; these should be used with care
I had a slightly different problem. Instead of incrementing a local variable in the forEach, I needed to assign an object to the local variable.
I solved this by defining a private inner domain class that wraps both the list I want to iterate over (countryList) and the output I hope to get from that list (foundCountry). Then using Java 8 "forEach", I iterate over the list field, and when the object I want is found, I assign that object to the output field. So this assigns a value to a field of the local variable, not changing the local variable itself. I believe that since the local variable itself is not changed, the compiler doesn't complain. I can then use the value that I captured in the output field, outside of the list.
Domain Object:
public class Country {
private int id;
private String countryName;
public Country(int id, String countryName){
this.id = id;
this.countryName = countryName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
}
Wrapper object:
private class CountryFound{
private final List<Country> countryList;
private Country foundCountry;
public CountryFound(List<Country> countryList, Country foundCountry){
this.countryList = countryList;
this.foundCountry = foundCountry;
}
public List<Country> getCountryList() {
return countryList;
}
public void setCountryList(List<Country> countryList) {
this.countryList = countryList;
}
public Country getFoundCountry() {
return foundCountry;
}
public void setFoundCountry(Country foundCountry) {
this.foundCountry = foundCountry;
}
}
Iterate operation:
int id = 5;
CountryFound countryFound = new CountryFound(countryList, null);
countryFound.getCountryList().forEach(c -> {
if(c.getId() == id){
countryFound.setFoundCountry(c);
}
});
System.out.println("Country found: " + countryFound.getFoundCountry().getCountryName());
You could remove the wrapper class method "setCountryList()" and make the field "countryList" final, but I did not get compilation errors leaving these details as-is.
To have a more general solution, you can write a generic Wrapper class:
public static class Wrapper<T> {
public T obj;
public Wrapper(T obj) { this.obj = obj; }
}
...
Wrapper<Integer> w = new Wrapper<>(0);
this.forEach(s -> {
s.setOrdinal(w.obj);
w.obj++;
});
(this is a variant of the solution given by Almir Campos).
In the specific case this is not a good solution, as Integer is worse than int for your purpose, anyway this solution is more general I think.

Categories

Resources