Java 8 stream short circuit manually [duplicate] - performance

This question already has answers here:
Limit a stream by a predicate
(19 answers)
Closed 6 years ago.
Is there any way to manually short circuit a stream (like in findFirst)?
Example:
Imagine a huge dictionary ordered by word size and alphabet:
cat
... (many more)
lamp
mountain
... (many more)
Only ready and compute the file from beginning, return immediately when line size exceeds 4:
read cat, compute cat
...
read tree, compute lamp
read mountain, return
The following code is very concise but does not take into advantage the order of the stream, it has to ready every line:
try (Stream<String> lines = Files.lines(Paths.get(DICTIONARY_PATH))) {
return lines
// filter for words with the correct size
.filter(line -> line.length() == 4)
// do stuff...
.collect(Collectors.toList());
}

Answer based on Limit a stream by a predicate, processing correctly stops when predicate returns false. Hopefully this method comes available in Java 9:
private static List<String> getPossibleAnswers(int numberOfChars, char[][] possibleChars) throws IOException {
try (Stream<String> lines = Files.lines(Paths.get(DICTIONARY_PATH)) {
return takeWhile(lines, line -> line.length() <= numberOfChars)
// filter length
.filter(line -> line.length() == numberOfChars)
// do stuff
.collect(Collectors.toList());
}
}
static <T> Spliterator<T> takeWhile(Spliterator<T> splitr, Predicate<? super T> predicate) {
return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) { boolean stillGoing = true;
#Override
public boolean tryAdvance(Consumer<? super T> consumer) {
if (stillGoing) {
boolean hadNext = splitr.tryAdvance(elem -> {
if (predicate.test(elem)) {
consumer.accept(elem);
} else {
stillGoing = false;
}
});
return hadNext && stillGoing;
}
return false;
}
};
}
static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> predicate) {
return StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false);
}

Related

Unchecked call to ifPresent inspection, why? [duplicate]

This question already has answers here:
What is a raw type and why shouldn't we use it?
(16 answers)
Closed 3 years ago.
My code:
public static boolean searchLineOnLogFile(String...keywords)
{
Collection select = null;
try (final Stream<String> lines = Files.lines(get(getServerLog().toString())))
{
select = CollectionUtils.select(lines.collect(Collectors.toCollection(LinkedList::new)),
new Predicate()
{
public boolean evaluate(Object object)
{
String line = (String) object;
return Arrays.stream(keywords).allMatch(line::contains);
}
});
} catch (IOException e)
{
e.printStackTrace();
Assert.fail(e.getMessage());
}
select.stream().findFirst().ifPresent(firstLine -> LogAutomation.info((String)firstLine));
return select.size() > 0;
}
select.stream().findFirst().ifPresent(firstLine -> log.info((String)firstLine));
Why I get 'uncheck call to isPresent' inspection ? how can I improve my code?
full inspection message
from what I 'v read all the idea is to avoid null check:
"So instead of writing something like:
if(optional.isPresent){
doSomething(optional.get);
}
You can write:
optional.ifPresent(val->doSomething(val));
or if you prefer:
optional.ifPresent(this::doSomething);
You can use Optional.ofNullable, as answered by Butiri.
You can also use Objects.requireNonNullElse.
With this second case you can define a default value if is empty.
Example:
public class Main {
public static void main(String[] args) {
Collection<Integer> select = null;
if (Math.random() > 0.5) {
select = Arrays.asList(1, 2, 3);
}
Objects.requireNonNullElse(select, Collections.singletonList(99)).stream().
findFirst().
ifPresent(e -> System.out.println("found: " + e));
}
}
The warning is because the select can be null. Can be fixed by Optional.ofNullable
Optional.ofNullable(select).stream().findFirst().ifPresent(firstLine -> LogAutomation.info((String) firstLine));

adding parallell to a stream causes NullPointerException

I'm trying to get my head around Java streams. It was my understanding that they provide an easy way to parallellize behaviour, and that also not all operations benefit from parallellization, but that you always have the option to do it by just slapping .parallell() on to an existing stream. This might make the stream go slower in some cases, or return the elements in a different order at the end etc, but you always have the option to parallellize a stream. That's why I got confused when I changed this method:
public static List<Integer> primeSequence() {
List<Integer> list = new LinkedList<Integer>();
IntStream.range(1, 10)
.filter(x -> isPrime(x))
.forEach(list::add);
return list;
}
//returns {2,3,5,7}
to this:
public static List<Integer> primeSequence() {
List<Integer> list = new LinkedList<Integer>();
IntStream.range(1, 10).parallel()
.filter(x -> isPrime(x))
.forEach(list::add);
return list;
}
//throws NullPointerException();
I thought all streams were serial unless otherwise stated and parallel() just made then execute in parallel. What am I missing here? Why does it throw an Exception?
There is one significant issue with your initial primeSequence method implementation - you mix stream iteration with outer list modification. You should avoid using streams that way, otherwise you will face a lot of problems. Like the one you have described. If you take a look at how add(E element) method is implemented you will see something like this:
public boolean add(E e) {
this.linkLast(e);
return true;
}
void linkLast(E e) {
LinkedList.Node<E> l = this.last;
LinkedList.Node<E> newNode = new LinkedList.Node(l, e, (LinkedList.Node)null);
this.last = newNode;
if (l == null) {
this.first = newNode;
} else {
l.next = newNode;
}
++this.size;
++this.modCount;
}
If you use CopyOnWriteArrayList instead of a LinkedList in your example, there will be no NullPointerException thrown - only because CopyOnWriteArrayList uses locking for multithread execution synchronization:
public boolean add(E e) {
ReentrantLock lock = this.lock;
lock.lock();
boolean var6;
try {
Object[] elements = this.getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
this.setArray(newElements);
var6 = true;
} finally {
lock.unlock();
}
return var6;
}
But it is still not the best way to utilize parallel stream.
Correct way to use Stream API
Consider following modification to your code:
public static List<Integer> primeSequence() {
return IntStream.range(1, 10)
.parallel()
.filter(x -> isPrime(x))
.boxed()
.collect(Collectors.toList());
}
Instead of modifying some outer list (of any kind) we are collecting the result and return a final list. You can transform any list to a stream using .stream() method and you don't have to worry about initial list - all operation you will apply to that list won't modify the input and the result will be a copy of the input list.
I hope it helps.

I have a long time to stay at making some RxJava codes better to average some data

I have a collection of data like dummy below
class Place {
userId,
price
}
That means a collection of some places.
Use-case:
There is a user with userId and login.
How to calc average place-price that equal to userId ?
RxJava is nice and I have tried filter and toList, however it is not so performance nice.
Observable.fromIterable(places)
.subscribeOn(Schedulers.newThread())
.filter(new Predicate<Place>() {
#Override
public boolean test(Place place) throws Exception {
return place.userId == global.login.userId;
}
})
.toList()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<Place>>() {
#Override
public void accept(List<Place> filteredPlace) throws Exception {
//Here I have to use loop to do math-average, it is not nice to average.
}
});
If the places is something that is already available in-memory, you can rearrange the evaluation such as this:
Observable.just(places)
.subscribeOn(Schedulers.computation())
.map((Iterable<Place> list) -> {
double sum = 0.0;
int count = 0;
for (Place p : list) {
if (p.userId == global.login.userId) {
sum += p.price;
count++;
}
}
return sum / count;
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(average -> { /* display average */ });
If the sequence of places becomes available over time (through an Observable):
Observable<Place> places = ...
places
.observeOn(Schedulers.computation())
.filter((Place p) -> p.userId == global.login.userId)
.compose(o -> MathObservable.averageDouble(o.map(p -> p.price)))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(average -> { /* display average */ });
MathObservable is part of the RxJava 2 Extensions library.

BASH brace expansion algorithm

I am stuck on this algorithmic question :
design an algorithm that parse an expression like this :
"((a,b,cy)n,m)" should give :
an - bn - cyn - m
The expression can nest, therefore :
"((a,b)o(m,n)p,b)" parses to ;
aomp - aonp - bomp - bonp - b.
I thought of using stacks, but it is too complicated.
thanks.
You can parse it with a Recursive Descent Parser.
Let's say the comma separated strings are components, so for an expression ((a, b, cy)n, m), (a, b, cy)n and m are two components. a, b and cy are also components. So this is a recursive definition.
For a component (a, b, cy)n, let's say (a, b, cy) and n are two component parts of the component. Component parts will later be combined to produce final result (i.e., an - bn - cyn).
Let's say an expression is comma separated components, for example, (a, cy)n, m is an expression. It has two components (a, cy)n and m, and the component (a, cy)n has two component parts (a, cy) and n, and component part (a, cy) is a brace expression containing a nested expression: a, cy, which also has two components a and cy.
With these definitions (you might use other terms), we can write down the grammar for your expression:
expression = component, component, ...
component = component_part component_part ...
component_part = letters | (expression)
One line is one grammar rule. The first line means an expression is a list of comma separated components. The second line means a component can be constructed with one or more component parts. The third line means a component part can be either a continuous sequence of letters or a nested expression inside a pair of braces.
Then you can use a Recursive Descent Parser to solve your problem with the above grammar.
We will define one method/function for each grammar rule. So basically we will have three methods ParseExpression, ParseComponent, ParseComponentPart.
Algorithm
As I stated above, an expression is comma separated components, so in our ParseExpression method, it simply calls ParseComponent, and then check if the next char is comma or not, like this (I'm using C#, I think you can easily convert it to other languages):
private List<string> ParseExpression()
{
var result = new List<string>();
while (!Eof())
{
// Parsing a component will produce a list of strings,
// they are added to the final string list
var items = ParseComponent();
result.AddRange(items);
// If next char is ',' simply skip it and parse next component
if (Peek() == ',')
{
// Skip comma
ReadNextChar();
}
else
{
break;
}
}
return result;
}
You can see that, when we are parsing an expression, we recursively call ParseComponent (it will then recursively call ParseComponentPart). It's a top-down approach, that's why it's called Recursive Descent Parsing.
ParseComponent is similar, like this:
private List<string> ParseComponent()
{
List<string> leftItems = null;
while (!Eof())
{
// Parse a component part will produce a list of strings (rightItems)
// We need to combine already parsed string list (leftItems) in this component
// with the newly parsed 'rightItems'
var rightItems = ParseComponentPart();
if (rightItems == null)
{
// No more parts, return current result (leftItems) to the caller
break;
}
if (leftItems == null)
{
leftItems = rightItems;
}
else
{
leftItems = Combine(leftItems, rightItems);
}
}
return leftItems;
}
The combine method simply combines two string list:
// Combine two lists of strings and return the combined string list
private List<string> Combine(List<string> leftItems, List<string> rightItems)
{
var result = new List<string>();
foreach (var leftItem in leftItems)
{
foreach (var rightItem in rightItems)
{
result.Add(leftItem + rightItem);
}
}
return result;
}
Then is the ParseComponentPart:
private List<string> ParseComponentPart()
{
var nextChar = Peek();
if (nextChar == '(')
{
// Skip '('
ReadNextChar();
// Recursively parse the inner expression
var items = ParseExpression();
// Skip ')'
ReadNextChar();
return items;
}
else if (char.IsLetter(nextChar))
{
var letters = ReadLetters();
return new List<string> { letters };
}
else
{
// Fail to parse a part, it means a component is ended
return null;
}
}
Full Source Code (C#)
The other parts are mostly helper methods, full C# source code is listed below:
using System;
using System.Collections.Generic;
using System.Text;
namespace Examples
{
public class BashBraceParser
{
private string _expression;
private int _nextCharIndex;
/// <summary>
/// Parse the specified BASH brace expression and return the result string list.
/// </summary>
public IList<string> Parse(string expression)
{
_expression = expression;
_nextCharIndex = 0;
return ParseExpression();
}
private List<string> ParseExpression()
{
// ** This part is already posted above **
}
private List<string> ParseComponent()
{
// ** This part is already posted above **
}
private List<string> ParseComponentPart()
{
// ** This part is already posted above **
}
// Combine two lists of strings and return the combined string list
private List<string> Combine(List<string> leftItems, List<string> rightItems)
{
// ** This part is already posted above **
}
// Peek next char without moving the cursor
private char Peek()
{
if (Eof())
{
return '\0';
}
return _expression[_nextCharIndex];
}
// Read next char and move the cursor to next char
private char ReadNextChar()
{
return _expression[_nextCharIndex++];
}
private void UnreadChar()
{
_nextCharIndex--;
}
// Check if the whole expression string is scanned.
private bool Eof()
{
return _nextCharIndex == _expression.Length;
}
// Read a continuous sequence of letters.
private string ReadLetters()
{
if (!char.IsLetter(Peek()))
{
return null;
}
var str = new StringBuilder();
while (!Eof())
{
var ch = ReadNextChar();
if (char.IsLetter(ch))
{
str.Append(ch);
}
else
{
UnreadChar();
break;
}
}
return str.ToString();
}
}
}
Use The Code
var parser = new BashBraceParser();
var result = parser.Parse("((a,b)o(m,n)p,b)");
var output = String.Join(" - ", result);
// Result: aomp - aonp - bomp - bonp - b
Console.WriteLine(output);
public class BASHBraceExpansion {
public static ArrayList<StringBuilder> parse_bash(String expression, WrapperInt p) {
ArrayList<StringBuilder> elements = new ArrayList<StringBuilder>();
ArrayList<StringBuilder> result = new ArrayList<StringBuilder>();
elements.add(new StringBuilder(""));
while(p.index < expression.length())
{
if (expression.charAt(p.index) == '(')
{
p.advance();
ArrayList<StringBuilder> temp = parse_bash(expression, p);
ArrayList<StringBuilder> newElements = new ArrayList<StringBuilder>();
for(StringBuilder e : elements)
{
for(StringBuilder t : temp)
{
StringBuilder s = new StringBuilder(e);
newElements.add(s.append(t));
}
}
System.out.println("elements :");
elements = newElements;
}
else if (expression.charAt(p.index) == ',')
{
result.addAll(elements);
elements.clear();
elements.add(new StringBuilder(""));
p.advance();
}
else if (expression.charAt(p.index) == ')')
{
p.advance();
result.addAll(elements);
return result;
}
else
{
for(StringBuilder sb : elements)
{
sb.append(expression.charAt(p.index));
}
p.advance();
}
}
return elements;
}
public static void print(ArrayList<StringBuilder> list)
{
for(StringBuilder s : list)
{
System.out.print(s + " * ");
}
System.out.println();
}
public static void main(String[] args) {
WrapperInt p = new WrapperInt();
ArrayList<StringBuilder> list = parse_bash("((a,b)o(m,n)p,b)", p);
//ArrayList<StringBuilder> list = parse_bash("(a,b)", p);
WrapperInt q = new WrapperInt();
ArrayList<StringBuilder> list1 = parse_bash("((a,b,cy)n,m)", q);
ArrayList<StringBuilder> list2 = parse_bash("((a,b)dr(f,g)(k,m),L(p,q))", new WrapperInt());
System.out.println("*****RESULT : ******");
print(list);
print(list1);
print(list2);
}
}
public class WrapperInt {
public WrapperInt() {
index = 0;
}
public int advance()
{
index ++;
return index;
}
public int index;
}
// aomp - aonp - bomp - bonp - b.

Java8 StreamFilter within List

I have something like this:
// common code without java8-closures/stream-api (this works):
public static List<Person> getFilteredRes_OLD(List<Person>all, List<String> names){
List<Person> pos = new ArrayList<>();
for(Person e: all){
for(String n: names){
if(Person.isFemale(n).test(e)){
pos.add(e);
}
}
}
return pos;
}
public static Predicate<Person> isFemale(String test) {
return p -> p.getFirstName()!=null && p.getFirstName().equalsIgnoreCase(test);
}
Now, I want to use the new Stream-filter API in Java 8:
// JAVA 8 code (this works, but only for a specified filter-value):
public static List<Person> getFilteredRes_NEW(List<Person>all, List<String> names){
return all.stream()
// how can I put the list 'names" into the filter-Method
// I do not want to test only for 'Lisa' but for the wohle "names"-list
.filter( Person.isFemale("Lisa") )
.collect(Collectors.<Person>toList());
return pos;
}
My Question for getFilteredRes_NEW() is:
How can I put the list of 'names" into the filter-Method?
I do not want to test only for 'Lisa' but for the wohle "names"-list within the stream.
Here's, I think, the filter instruction you want:
.filter(person -> names.stream().anyMatch(
name -> Person.isFemale(name).test(person)))
For each person, it tests if there is at least one name N in the list of names for which the Person.isFemale(N).test(P) returns true.
It would be much simpler, and create less instances of Predicate, if you simply had a method
public boolean isFemale(Person p, String name) {
return p.getFirstName() != null && p.getFirstName().equalsIgnoreCase(test);
}
The code would become
.filter(person -> names.stream().anyMatch(name -> isFemale(person, name)))
You should also rename isFemale(), because it doesn't test at all if the person is female. It tests if a person has a given first name (ignoring the case).

Resources