Affect some logic lists using java stream [closed] - java

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I am trying to change the loop to Java streams.
For example,
interface Logic {
int apply(int value);
}
public class AddOneLogic implements Logic {
#Override
public int apply(int value) {
return value + 1;
}
}
public class AddTwoLogic implements Logic {
#Override
public int apply(int value) {
return value + 2;
}
}
Using a loop to apply a Logic looks like
List<Logic> logics = new ArrayList<>();
logics.add(new AddOneLogic());
logics.add(new AddTwoLogic());
int init = 1;
I want to change to streams below. Is there any better way to do it?
int result = init;
for (Logic logic : logics) {
result = logic.apply(result);
}

As #duffymo mentioned in the comments, these classes aren't particularly useful and they could be replaced with Function<Integer, Integer>s and lambda expressions to define them.
In that case, you may want to reduce a list/stream of Functions by Function::andThen,
Function<Integer, Integer> addOneFunction = i -> i + 1;
Function<Integer, Integer> addTwoFunction = i -> i + 2;
Function<Integer, Integer> function =
Stream.of(addOneFunction, addTwoFunction)
.reduce(Function.identity(), Function::andThen);
so you would get a composed function to work with
Integer result = function.apply(init);
// ((1 + 1) + 2) = 4

You can do it with Stream and AtomicInteger and getAndSet(int) method as below,
AtomicInteger result = new AtomicInteger(1);
logics.stream().forEach(ele-> result.getAndSet(ele.apply(result.get())));
// result = ((1+1)+2)=4
Better option would be to use Function,
Function<Integer, Integer> addOne = i -> i + 1;
Function<Integer, Integer> addTwo = i -> i + 2;
List<Function<Integer, Integer>> logics = new ArrayList<>();
logics.add(addOne);
logics.add(addTwo);
AtomicInteger result = new AtomicInteger(1);
logics.stream().forEach(ele-> result.getAndSet(ele.apply(result.get())));
You can even avoid logics list and use andThen method as below,
Function<Integer, Integer> add = addOne.andThen(addTwo);
result = add.apply(1);
Hope it helps..!!

As others have already mentioned: The intention behind the question might be distorted by the attempt to simplify the question so that it can be posted here. The Logic interface does not really make sense, because it could be replaced with an IntUnaryOperator.
Not with a Function<Integer, Integer> - that's a different thing!
But I'll (also) make some assumptions when trying to answer the question:
The Logic interface is merely a placeholder for an interface that has to be retained in its current form
Several Logic instances can sensibly be combined in order to yield an new Logic
The goal is not to "apply streams for the streams sake", but to create sensible, usable classes and methods (and it's a pity that this is worth mentioning...)
If this is the case, then I'd suggest creating a CombinedLogic class that simply offers a method for combining several Logic objects to create the combined one.
It could also be a concrete class that internally stores a List<Logic>. This might be handy in order to modify a combined logic later, as in combinedLogic.setElement(42, new OtherLogic());. But a public class with a modifiable state should be thought through carefully...
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CombinedLogicExample {
public static void main(String[] args) {
List<Logic> logics = new ArrayList<>();
logics.add(new AddOneLogic());
logics.add(new AddTwoLogic());
Logic combined = CombinedLogic.of(logics);
// Alternatively:
// Logic logic1 = new AddOneLogic();
// Logic logic2 = new AddTwoLogic();
// Logic combined = CombinedLogic.of(logic1, logic2);
int init = 1;
int result = combined.apply(init);
System.out.println(result);
}
}
class CombinedLogic {
static Logic of(Logic... logics) {
return of(Arrays.asList(logics));
}
static Logic of(Iterable<? extends Logic> logics) {
return a -> {
int result = a;
for (Logic logic : logics) {
result = logic.apply(result);
}
return result;
};
}
}
interface Logic {
int apply(int value);
}
class AddOneLogic implements Logic {
#Override
public int apply(int value) {
return value + 1;
}
}
class AddTwoLogic implements Logic {
#Override
public int apply(int value) {
return value + 2;
}
}

Related

Generic Supplier for n Getters Across Collection

I have a collection of Java objects where I want to run a single function across multiple values I might find in some of the object's member variables. I'm looking for a nice way to pass in which getter should be used so I can have one method do all that work. I was thinking about something like a Supplier, but that would mean I have to have one per instance of the class. Here's an example of what I'm trying to do (only I would like to do this without the if statement or with potentially n getters a switch statement:
import java.util.ArrayList;
import java.util.List;
public class TestSupplier {
private int varA;
private int varB;
public TestSupplier(int varA, int varB) {
this.varA = varA;
this.varB = varB;
}
public int getA() {
return this.varA;
}
public int getB() {
return this.varB;
}
public static void main(String[] args) {
List<TestSupplier> testList = new ArrayList<>();
testList.add(new TestSupplier(1, 11));
testList.add(new TestSupplier(2, 22));
// Can I pass something like a generic supplier instead of a bool?
TestSupplier.someCollectorFunction(testList, true);
TestSupplier.someCollectorFunction(testList, false);
}
public static void someCollectorFunction(List<TestSupplier> list, boolean isA /* what if I want more than one getter*/) {
int sum = 0;
for (TestSupplier obj: list) {
// This is where I wish I could have a generic supplier or something
if (isA) {
sum = sum + obj.getA();
}
else {
sum = sum + obj.getB();
}
}
System.out.println("I have a sum: " + sum);
}
}
Is there something is Java's functional API that would let me do this?
It sounds like what you want is
ToIntFunction<TestSupplier> fn = isA ? TestSupplier::getA : TestSupplier::getB;
for (TestSupplier obj: list) {
sum += fn.applyAsInt(obj);
}
It's up to you whether you consider that an improvement.
You could also pass in the ToIntFunction instead of the boolean, passing in TestSupplier::getA instead of true etc.

Functions instead of static utility methods

Despite Functions being around in Java since Java 8, I started playing with them only recently. Hence this question may sound a little archaic, kindly excuse.
At the outset, I am talking of a pure function written completely in conformance of Functional Programming definition: deterministic and immutable.
Say, I have a frequent necessity to prepend a string with another static value. Like the following for example:
private static Function<String, String> fnPrependString = (s) -> {
return "prefix_" + s;
};
In the good old approach, the Helper class and its static methods would have been doing this job for me.
The question now is, whether I can create these functions once and reuse them just like helper methods.
One threat is that of thread-safety. And I used a simple test to check this with this JUnit test:
package com.me.expt.lt.test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Consumer;
import java.util.function.Function;
import org.junit.jupiter.api.Test;
import com.vmlens.api.AllInterleavings;
public class TestFunctionThreadSafety {
private static Function<String, String> fnPrepend = (s) -> {
System.out.println(s);
return new StringBuffer("prefix_").append(s).toString();
};
#Test
public void testThreadSafety() throws InterruptedException {
try (AllInterleavings allInterleavings = new AllInterleavings(
TestFunctionThreadSafety.class.getCanonicalName());) {
ConcurrentMap<String, Integer> resultMap = new ConcurrentHashMap<String, Integer>();
while (allInterleavings.hasNext()) {
int runSize = 5;
Thread[] threads = new Thread[runSize];
ThreadToRun[] ttrArray = new ThreadToRun[runSize];
StringBuffer sb = new StringBuffer("0");
for (int i = 0; i < runSize; i++) {
if (i > 0)
sb.append(i);
ttrArray[i] = new ThreadToRun();
ttrArray[i].setS(sb.toString());
threads[i] = new Thread(ttrArray[i]);
}
for (int j = 0; j < runSize; j++) {
threads[j].start();
}
for (int j = 0; j < runSize; j++) {
threads[j].join();
}
System.out.println(resultMap);
StringBuffer newBuffer = new StringBuffer("0");
for (int j = 0; j < runSize; j++) {
if(j>0)
newBuffer.append(j);
assertEquals("prefix_" + newBuffer, ttrArray[j].getResult(), j + " fails");
}
}
}
}
private static class ThreadToRun implements Runnable {
private String s;
private String result;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public String getResult() {
return result;
}
#Override
public void run() {
this.result = fnPrepend.apply(s);
}
}
}
I am using vmlens. I can tune my test by changing the runSize variable by as good a number as I choose so that the randomness can be checked. The objective is to see if these multiple threads using the same function mix up their inputs because of concurrent access. The test did not return any negative results. Please also do comment on whether the test meets the goals.
I also tried to understand the internal VM end of how lambdas are executed from here. Even as I look for somewhat simpler articles that I can understand these details faster, I did not find anything that says "Lambdas will have thread safety issues".
Assuming the test case meets my goal, the consequential questions are:
Can we replace the static helper classes with function variables immutable and deterministic functions like fnPrepend? The objective is to simply provide more readable code and also of course to move away from the "not so Object oriented" criticism about static methods.
Is there is a source of simpler explanation to how Lambdas work inside the vm?
Can the results above with a Function<InputType, ResultType> be applied to a Supplier<SuppliedType> and a Consumer<ConsumedType> also?
Some more familiarity with functions and the bytecode will possibly help me answer these questions. But a knowledge exchange forum like this may get me an answer faster and the questions may trigger more ideas for the readers.
Thanks in advance.
Rahul
I really don't think you, as a user, need to go to such lengths to prove the JVM's guarantees about lambdas. Basically, they are just like any other method to the JVM with no special memory or visibility effects :)
Here's a shorter function definition:
private static Function<String, String> fnPrepend = s -> "prefix_" + s;
this.result = fnPrepend.apply(s);
... but don't use a lambda just for the sake of it like this - it's just extra overhead for the same behaviour. Assuming the real usecase has a requirement for a Function, we can use Method References to call the static method. This gets you the best of both worlds:
// Available as normal static method
public static String fnPrepend(String s) {
return "prefix_" + s;
}
// Takes a generic Function
public static void someMethod(UnaryOperator<String> prefixer) {
...
}
// Coerce the static method to a function
someMethod(Util::fnPrepend);

Java multithreading, accessing list from separate classes

Just to start off, I'm pretty inept at Java and especially multithreading, so what I'm asking might sound a bit ordinary. I am attempting to create a program in which I create three threads which each accomplish the specific task of depicting certain values between ten integers, such as average, deviation, etc. How would I approach this?
I am attempting to create four classes, one for the main program, and three for each of the calculations of the values between each: class "Average" for the average of the ten numbers in the array, class "Median" for the median, etc. The code for the other 3 classes I can easily write, no problem there. My main problem is that since the list "integers" is not available outside the class, I can't write the code for finding each of the values I need in the three programs.
Is there a better way to write this so I can actually access the list from inside the classes for each of the threads?
import java.util.*;
public class ThreadDemo
{
public static void main(String[] args)
{
Random number = new Random();
List integers = new ArrayList();
for (int i = 0; i < 10; i++)
{
integers.add(number.nextInt(101));
}
Thread average = new Thread(new Average());
Thread median = new Thread(new Median());
Thread deviation = new Thread(new Deviation());
average.start();
median.start();
deviation.start();
}
}
class Average extends Thread
{
public void run()
{
// code for finding average
}
}
class Median extends Thread
{
public void run()
{
// code for finding median
}
}
class Deviation extends Thread
{
public void run()
{
// code for finding deviation
}
}
There are a lot of options to achieve what you are trying to do. I will outline two:
each computation method implementing the Callable interface and taking data into the instance constructor;
each computation method implementing the Function interface and passing data into the call via the closure.
It is generally advisable to program to interfaces, that is require an interface as method argument. All below examples follow this by implementing Callable or Function and working with those high level interfaces elsewhere. The code for both cases looks very similar with the main difference being the remapping of Function to Callable in the latter case using the closure state.
Let's start with some common utilities (statics for brevity only):
The following method will create a Collection of 100 random integers in [0,100]:
private static Collection<Integer> ints() {
Random random = new Random();
return random.ints(100, 0, 100)
.boxed()
.collect(Collectors.toList());
}
The following method will execute a collection of Callables concurrently on a cached executor pool. Each callable is generic and will deliver a double value. Those values (in random order) will be collected and returned as a list:
private static List<Double> concurrently(Collection<Callable<Double>> callables) throws InterruptedException, ExecutionException {
ExecutorService executors = Executors.newCachedThreadPool();
Collection<Future<Double>> futures = executors.invokeAll(callables);
List<Double> res = new ArrayList<>();
for (Future<Double> future: futures) {
res.add(future.get());
}
executors.shutdownNow();
return res;
}
Now let's get back to the core logic.
Case 1: Implementing Callable
class Averager<V extends Number> implements Callable<Double> {
private final Collection<V> values = new ArrayList<>();
Averager(Collection<V> values) {
this.values.addAll(values);
}
#Override
public Double call() {
double sum = 0.0;
for (V value : values) {
sum += value.doubleValue();
}
return Double.valueOf(sum / values.size());
}
}
class Medianer<V extends Number> implements Callable<Double> {
private final Collection<V> values = new ArrayList<>();
Medianer(Collection<V> values) {
this.values.addAll(values);
}
#Override
public Double call() {
List<V> sorted = new ArrayList<>(values);
sorted.sort(Comparator.comparingDouble(Number::doubleValue));
// TODO treat odd/even number of elements separately
return Double.valueOf(sorted.get(sorted.size() / 2).doubleValue());
}
}
Note: whenever you take a collection as a constructor argument, do not store the reference to the original collection provided in a private field, copy values. If collections are very large, do not pass them to constructor or make unmodifiable.
#Test
public void usingCallable() throws InterruptedException, ExecutionException {
Collection<Integer> values = ints();
Collection<Callable<Double>> callables = new ArrayList<>();
callables.add(new Averager<>(values));
callables.add(new Medianer<>(values));
List<Double> res = concurrently(callables);
System.out.println(res);
}
Case 2: Implementing Function
class Averager<V extends Number> implements Function<Collection<V>, Double> {
#Override
public Double apply(Collection<V> values) {
double sum = 0.0;
for (V value : values) {
sum += value.doubleValue();
}
return Double.valueOf(sum / values.size());
}
}
class Medianer<V extends Number> implements Function<Collection<V>, Double> {
#Override
public Double apply(Collection<V> values) {
List<V> sorted = new ArrayList<>(values);
sorted.sort(Comparator.comparingDouble(Number::doubleValue));
// TODO treat odd/even number of elements separately
return Double.valueOf(sorted.get(sorted.size() / 2).doubleValue());
}
}
#Test
public void usingFunction() throws InterruptedException, ExecutionException {
Collection<Integer> values = ints();
Collection<Function<Collection<Integer>, Double>> functions = new ArrayList<>();
functions.add(new Averager<>());
functions.add(new Medianer<>());
List<Callable<Double>> callables = functions.stream().map(f -> (Callable<Double>) () -> f.apply(values)).collect(Collectors.toList());
List<Double> res = concurrently(callables);
System.out.println(res);
}
I personally prefer the latter one because your computation methods become generic functions, that is implementing the generic Function interface and can be used in other contexts.
Reworking case 1 and 2 with lambdas
You can do some interesting things with lambdas here. For the case of functions, you can just predefine them as lambdas instead of constructing new instances of specifically defined class:
static final Function<Collection<Integer>, Double> averager = (values) -> {
double sum = 0.0;
for (Integer value : values) {
sum += value.doubleValue();
}
return Double.valueOf(sum / values.size());
};
static final Function<Collection<Integer>, Double> medianer = (values) -> {
List<Integer> sorted = new ArrayList<>(values);
sorted.sort(Comparator.comparingDouble(Number::doubleValue));
// TODO treat odd/even number of elements separately
return Double.valueOf(sorted.get(sorted.size() / 2).doubleValue());
};
Followed later by:
Collection<Function<Collection<Integer>, Double>> functions = new ArrayList<>();
functions.add(averager);
functions.add(medianer);
For the case of callable you can nicely inline them:
Collection<Callable<Double>> callables = new ArrayList<>();
callables.add(() -> {
double sum = 0.0;
for (Integer value : values) {
sum += value.doubleValue();
}
return Double.valueOf(sum / values.size());
});
callables.add(() -> {
List<Integer> sorted = new ArrayList<>(values);
sorted.sort(Comparator.comparingDouble(Number::doubleValue));
// TODO treat odd/even number of elements separately
return Double.valueOf(sorted.get(sorted.size() / 2).doubleValue());
});
Note how you do not need external declarations in the latter case.
Note: as you do not want your results in a random order you will need you function return a pair, e.g. Map.Entry, with a key and a value. But I will leave that to you to exercise.
A sample execution for one of those methods would print something like
[53.01,57.0]
You can pass as a constructor argument. Also, after starting the threads, you must call join, otherwise the main thread will not wait the others to finish:
average.start();
median.start();
deviation.start();
average.join();
median.join();
deviation.join();
```

using java streams in parallel with collect(supplier, accumulator, combiner) not giving expected results

I'm trying to find number of words in given string. Below is sequential algorithm for it which works fine.
public int getWordcount() {
boolean lastSpace = true;
int result = 0;
for(char c : str.toCharArray()){
if(Character.isWhitespace(c)){
lastSpace = true;
}else{
if(lastSpace){
lastSpace = false;
++result;
}
}
}
return result;
}
But, when i tried to 'parallelize' this with Stream.collect(supplier, accumulator, combiner) method, i am getting wordCount = 0. I am using an immutable class (WordCountState) just to maintain the state of word count.
Code :
public class WordCounter {
private final String str = "Java8 parallelism helps if you know how to use it properly.";
public int getWordCountInParallel() {
Stream<Character> charStream = IntStream.range(0, str.length())
.mapToObj(i -> str.charAt(i));
WordCountState finalState = charStream.parallel()
.collect(WordCountState::new,
WordCountState::accumulate,
WordCountState::combine);
return finalState.getCounter();
}
}
public class WordCountState {
private final boolean lastSpace;
private final int counter;
private static int numberOfInstances = 0;
public WordCountState(){
this.lastSpace = true;
this.counter = 0;
//numberOfInstances++;
}
public WordCountState(boolean lastSpace, int counter){
this.lastSpace = lastSpace;
this.counter = counter;
//numberOfInstances++;
}
//accumulator
public WordCountState accumulate(Character c) {
if(Character.isWhitespace(c)){
return lastSpace ? this : new WordCountState(true, counter);
}else{
return lastSpace ? new WordCountState(false, counter + 1) : this;
}
}
//combiner
public WordCountState combine(WordCountState wordCountState) {
//System.out.println("Returning new obj with count : " + (counter + wordCountState.getCounter()));
return new WordCountState(this.isLastSpace(),
(counter + wordCountState.getCounter()));
}
I've observed two issues with above code :
1. Number of objects (WordCountState) created are greater than number of characters in the string.
2. Result is always 0.
3. As per accumulator/consumer documentation, shouldn't the accumulator return void? Even though my accumulator method is returning an object, compiler doesn't complain.
Any clue where i might have gone off track?
UPDATE :
Used solution as below -
public int getWordCountInParallel() {
Stream<Character> charStream = IntStream.range(0, str.length())
.mapToObj(i -> str.charAt(i));
WordCountState finalState = charStream.parallel()
.reduce(new WordCountState(),
WordCountState::accumulate,
WordCountState::combine);
return finalState.getCounter();
}
You can always invoke a method and ignore its return value, so it’s logical to allow the same when using method references. Therefore, it’s no problem creating a method reference to a non-void method when a consumer is required, as long as the parameters match.
What you have created with your immutable WordCountState class, is a reduction operation, i.e. it would support a use case like
Stream<Character> charStream = IntStream.range(0, str.length())
.mapToObj(i -> str.charAt(i));
WordCountState finalState = charStream.parallel()
.map(ch -> new WordCountState().accumulate(ch))
.reduce(new WordCountState(), WordCountState::combine);
whereas the collect method supports the mutable reduction, where a container instance (may be identical to the result) gets modified.
There is still a logical error in your solution as each WordCountState instance starts with assuming to have a preceding space character, without knowing the actual situation and no attempt to fix this in the combiner.
A way to fix and simplify this, still using reduction, would be:
public int getWordCountInParallel() {
return str.codePoints().parallel()
.mapToObj(WordCountState::new)
.reduce(WordCountState::new)
.map(WordCountState::getResult).orElse(0);
}
public class WordCountState {
private final boolean firstSpace, lastSpace;
private final int counter;
public WordCountState(int character){
firstSpace = lastSpace = Character.isWhitespace(character);
this.counter = 0;
}
public WordCountState(WordCountState a, WordCountState b) {
this.firstSpace = a.firstSpace;
this.lastSpace = b.lastSpace;
this.counter = a.counter + b.counter + (a.lastSpace && !b.firstSpace? 1: 0);
}
public int getResult() {
return counter+(firstSpace? 0: 1);
}
}
If you are worrying about the number of WordCountState instances, note how many Character instances this solution does not create, compared to your initial approach.
However, this task is indeed suitable for mutable reduction, if you rewrite your WordCountState to a mutable result container:
public int getWordCountInParallel() {
return str.codePoints().parallel()
.collect(WordCountState::new, WordCountState::accumulate, WordCountState::combine)
.getResult();
}
public class WordCountState {
private boolean firstSpace, lastSpace=true, initial=true;
private int counter;
public void accumulate(int character) {
boolean white=Character.isWhitespace(character);
if(lastSpace && !white) counter++;
lastSpace=white;
if(initial) {
firstSpace=white;
initial=false;
}
}
public void combine(WordCountState b) {
if(initial) {
this.initial=b.initial;
this.counter=b.counter;
this.firstSpace=b.firstSpace;
this.lastSpace=b.lastSpace;
}
else if(!b.initial) {
this.counter += b.counter;
if(!lastSpace && !b.firstSpace) counter--;
this.lastSpace = b.lastSpace;
}
}
public int getResult() {
return counter;
}
}
Note how using int to represent unicode characters consistently, allows to use the codePoint() stream of a CharSequence, which is not only simpler, but also handles characters outside the Basic Multilingual Plane and is potentially more efficient, as it doesn’t need boxing to Character instances.
When you implemented stream().collect(supplier, accumulator, combiner) they do return void (combiner and accumulator). The problem is that this:
collect(WordCountState::new,
WordCountState::accumulate,
WordCountState::combine)
In your case actually means (just the accumulator, but same goes for the combiner):
(wordCounter, character) -> {
WordCountState state = wc.accumulate(c);
return;
}
And this is not trivial to get indeed. Let's say we have two methods:
public void accumulate(Character c) {
if (!Character.isWhitespace(c)) {
counter++;
}
}
public WordCountState accumulate2(Character c) {
if (Character.isWhitespace(c)) {
return lastSpace ? this : new WordCountState(true, counter);
} else {
return lastSpace ? new WordCountState(false, counter + 1) : this;
}
}
For the them the below code will work just fine, BUT only for a method reference, not for lambda expressions.
BiConsumer<WordCountState, Character> cons = WordCountState::accumulate;
BiConsumer<WordCountState, Character> cons2 = WordCountState::accumulate2;
You can imagine it slightly different, via an class that implementes BiConsumer for example:
BiConsumer<WordCountState, Character> clazz = new BiConsumer<WordCountState, Character>() {
#Override
public void accept(WordCountState state, Character character) {
WordCountState newState = state.accumulate2(character);
return;
}
};
As such your combine and accumulate methods needs to change to:
public void combine(WordCountState wordCountState) {
counter = counter + wordCountState.getCounter();
}
public void accumulate(Character c) {
if (!Character.isWhitespace(c)) {
counter++;
}
}
First of all, would it not be easier to just use something like input.split("\\s+").length to get the word count?
In case this is an exercise in streams and collectors, let's discuss your implementation. The biggest mistake was pointed out by you already: Your accumulator and combiner should not return new instances. The signature of collect tells you that it expects BiConsumer, which do not return anything. Because you create new object in the accumulator, you never increase the count of the WordCountState objects your collector actually uses. And by creating a new object in the combiner you would discard any progress you would have made. This is also why you create more objects than characters in your input: one per character, and then some for the return values.
See this adapted implementation:
public static class WordCountState
{
private boolean lastSpace = true;
private int counter = 0;
public void accumulate(Character character)
{
if (!Character.isWhitespace(character))
{
if (lastSpace)
{
counter++;
}
lastSpace = false;
}
else
{
lastSpace = true;
}
}
public void combine(WordCountState wordCountState)
{
counter += wordCountState.counter;
}
}
Here, we do not create new objects in every step, but change the state of the ones we have. I think you tried to create new objects because your Elvis operators forced you to return something and/or you couldn't change the instance fields as they are final. They do not need to be final, though, and you can easily change them.
Running this adapted implementation sequentially now works fine, as we nicely look at the chars one by one and end up with 11 words.
In parallel, though, it fails. It seems it creates a new WordCountState for every char, but does not count all of them, and ends up at 29 (at least for me). This shows a basic flaw with your algorithm: Splitting on every character doesn't work in parallel. Imagine the input abc abc, which should result in 2. If you do it in parallel and do not specify how to split the input, you might end up with these chunks: ab, c a, bc, which would add up to 4.
The problem is that by parallelizing between characters (i.e. in the middle of words), you make your separate WordCountStates dependent on each other (because they would need to know which one come before them and whether it ended with a whitespace char). This defeats the parallelism and results in errors.
Aside from all that, it might be easier to implement the Collector interface instead of providing the three methods:
public static class WordCountCollector
implements Collector<Character, SimpleEntry<AtomicInteger, Boolean>, Integer>
{
#Override
public Supplier<SimpleEntry<AtomicInteger, Boolean>> supplier()
{
return () -> new SimpleEntry<>(new AtomicInteger(0), true);
}
#Override
public BiConsumer<SimpleEntry<AtomicInteger, Boolean>, Character> accumulator()
{
return (count, character) -> {
if (!Character.isWhitespace(character))
{
if (count.getValue())
{
String before = count.getKey().get() + " -> ";
count.getKey().incrementAndGet();
System.out.println(before + count.getKey().get());
}
count.setValue(false);
}
else
{
count.setValue(true);
}
};
}
#Override
public BinaryOperator<SimpleEntry<AtomicInteger, Boolean>> combiner()
{
return (c1, c2) -> new SimpleEntry<>(new AtomicInteger(c1.getKey().get() + c2.getKey().get()), false);
}
#Override
public Function<SimpleEntry<AtomicInteger, Boolean>, Integer> finisher()
{
return count -> count.getKey().get();
}
#Override
public Set<java.util.stream.Collector.Characteristics> characteristics()
{
return new HashSet<>(Arrays.asList(Characteristics.CONCURRENT, Characteristics.UNORDERED));
}
}
We use a pair (SimpleEntry) to keep the count and the knowledge about the last space. This way, we do not need to implement the state in the collector itself or write a param object for it. You can use this collector like this:
return charStream.parallel().collect(new WordCountCollector());
This collector parallelizes nicer than the initial implementation, but still varies in results (mostly between 14 and 16) because of the mentioned weaknesses in your approach.

Java Convert Object[] Array to Vector

What's the best way to convert an Object array to a Vector?
JDE < 1.5
public Vector getListElements()
{
Vector myVector = this.elements;
return myVector;
}
this.elements is an Object[]
Thanks,
rAyt
I should clarify my question
My target platform is a blackberry.
Collections aren't supported. Array.asList() isn't, either :/
Full Class
package CustomElements;
import net.rim.device.api.ui.component .*;
import net.rim.device.api.collection.util.*;
import net.rim.device.api.util.*;
import java.util.*;
public class ContactsList extends SortedReadableList implements KeywordProvider
{
// Constructor
public ContactsList(Vector contacts)
{
super(new ContactsListComparatorByFirstName());
loadFrom(contacts.elements());
}
// Add Element to ContactsSortedReadableList
void addElement(Object element)
{
doAdd(element);
}
public Vector getListElements()
{
return new Vector(Collection
Vector test = this.getElements();
}
// getKeywords
public String[] getKeywords(Object element)
{
return StringUtilities.stringToWords(((Contact)element).get_contactFirstName());
// return StringUtilities.stringToWords(element.toString());
}
// Comparator sorting Contact objects by name
final static class ContactsListComparatorByFirstName implements Comparator
{
public int compare(Object o1, Object o2)
{
// Sticky Entries Implementation
if(((ContactsListObject)o2).getSticky())
{
return 1;
} else
if (((ContactsListObject)o1).getSticky())
{
return -1;
} else
{
if(((ContactsListObject)o1).get_contactFirstName().compareTo(((ContactsListObject)o2).get_contactFirstName()) <0)
{
return -1;
}
if(((ContactsListObject)o1).get_contactFirstName().compareTo(((ContactsListObject)o2).get_contactFirstName()) >0)
{
return 1;
}
else
{
return 0;
}
}
}
}
}
return new Vector(Arrays.asList(elements));
Now, it may look as if you are copying the data twice, but you aren't. You do get one small temporary object (a List from asList), but this provides a view of the array. Instead of copying it, read and write operations go through to the original array.
It is possible to extends Vector and poke its protected fields. This would give a relatively simple way of having the Vector become a view of the array, as Arrays.asList does. Alternatively, just copying data into the fields. For Java ME, this is about as good as it gets without writing the obvious loop. Untested code:
return new Vector(0) {{
this.elementData = (Object[])elements.clone();
this.elementCount = this.elementData.length;
}};
Of course, you are probably better off with a List than a Vector. 1.4 has completed its End of Service Life period. Even 1.5 has completed most of its EOSL period.
In J2ME, you're stuck iterating over the array and add the elements one by one.
Vector v = new Vector();
for (int i = 0; i < this.elements.length; i++) {
v.add(this.elements[i]);
}
A simplified comparator which does basically the same thing.
final static class ContactsListComparatorByFirstName implements Comparator {
public int compare(Object o1, Object o2) {
// Sticky Entries Implementation
ContactsListObject clo2 = (ContactsListObject) o2;
ContactsListObject clo1 = (ContactsListObject) o1;
if (clo2.getSticky()) return 1;
if (clo1.getSticky()) return -1;
return clo1.get_contactFirstName().compareTo(clo2.get_contactFirstName());
}
}
Using generics and ?: it would be just
static final class ContactsListComparatorByFirstName implements Comparator<ContactsListObject> {
public int compare(ContactsListObject clo1, ContactsListObject clo2) {
return clo2.getSticky() ? 1 : // Sticky Entries Implementation
clo1.getSticky() ? -1 :
clo1.get_contactFirstName().compareTo(clo2.get_contactFirstName());
}
}
But to answer your question... (oh I see Tom has what I would put already)
imho your only viable option is:
public Vector getListElements()
Vector vector = new Vector(this.elements.length);
for (int i = 0; i < this.elements.length; i++) {
vector.add(this.elements[i]);
}
return vector;
}
Copy the array elements to the Vector, or
Use Arrays.asList(...) to return a List, which isn't exactly a Vector, but you should be coding the List interface anyway.
A reasonably concise way to do it is something like:
Object[] xx = { 1, "cat", new Point(100,200) };
Vector vv = new Vector(Arrays.asList(xx));
System.out.println("vv=="+vv.toString());
But y'all knew that already, I guess.

Categories