I'm writing a parser for a programming language, and I was thinking Java's takeWhile method might be perfect for grouping the lexical tokens into structures. As an example case, to get a stream of tokens representing a brace-delimited code block, I could write:
stream.dropWhile(t -> !t.equals("{")).takeWhile(t -> !t.equals("}")))
…Except, obviously that wouldn't work if the block in question had nested blocks, such as a function declaration. In a more imperative style, I might do this after the opening brace:
assert(openCurlyToken.equals("{");
List blockTokens = new ArrayList<String>();
blockTokens.add(openCurlyToken);
String token;
int braceLevel = 1;
while (braceLevel > 0) {
token = nextToken();
if (token.equals("{")) braceLevel++;
else if (token.equals("}")) braceLevel--;
blockTokens.add(t);
}
return blockTokens;
Kinda ugly, kinda verbose. What I'm hoping is there is a more concise way to do this kind of computation using Streams?
Related
I have two lists, allowedOU and parts. I need to know how to iterate through streams, check the condition and if it is true, include the element in a third list, and change the flag (heritable).
for (String part : parts) {
for (BeanOU it : allowedOU) {
if (part.startsWith("OU") && it.OU.equals(part.substring(3) && heritableFlag) {
list.add(part.substring(3, part.length()));
heritableFlag = it.heritable;
break;
}
}
}
I tried something like this
parts.stream()
.filter(parte -> allowedOU.stream()
.anyMatch(allowed -> (parte.startsWith("OU"))
&& allowed.OU.equals(parte.substring(3, parte.length()))
&& finalHeritableFlag))
.forEach(here we don't have it variable...)
"The results of the flow pipeline can be non-deterministic or incorrect if the behavior parameters of the flow operations are stateful."
"Most stream operations accept parameters that describe user-specified behavior, which are often lambda expressions. To preserve correct behavior, these behavior parameters should not interfere, and in most cases should be stateless. Such parameters are always instances of a functional interface such as Function, and are often lambda expressions or method references".
I leave this in case someone needs it!
an approximation to stop when a certain condition is met, it offers us is takeWhile
List<String> partsList = Arrays.asList(parts);
partsList = partsList.stream().filter((a->a.startsWith("OU"))).map(s->s.substring(3)).collect(Collectors.toList());
List<String> finalPartsList1 = partsList;
listOUallowedByUser = allowedOU.stream().takeWhile(allowed -> allowed.heritable).filter(f-> finalPartsList1.contains(f.OU)).map(a-> a.OU).collect(Collectors.toList());;
thanks for mark-rotteveel and alexander-ivanchenko :-)
I have a method that returns the average of a property over a number of model objects:
List<Activity> activities = ...;
double effortSum = 0;
double effortCount = 0;
activities.stream().forEach(a -> {
double effort = a.getEffort();
if (effort != Activity.NULL) {
effortCount++; < Compilation error, local variable
effortSum += effort; < Compilation error, local variable
}
});
But, the above attempt doesn't compile, as noted. The only solution that's coming to me is using an AtomicReference to a Double object, but that seems crufty, and adds a large amount of confusion to what should be a simple operation. (Or adding Guava and gaining AtomicDouble, but the same conclusion is reached.)
Is there a "best practice" strategy for modifying local variables using the new Java 8 loops?
Relevant code for Activity:
public class Activity {
public static final double NULL = Double.MIN_VALUE;
private double effort = NULL;
public void setEffort(double effort) { this.effort = effort; }
public double getEffort() { return this.effort; }
...
}
Is there a "best practice" strategy for modifying local variables using the new Java 8 loops?
Yes: don't. You can modify their properties -- though it's still a bad idea -- but you cannot modify them themselves; you can only refer to variables from inside a lambda if they are final or could be final. (AtomicDouble is indeed one solution, another is a double[1] that just serves as a holder.)
The correct way of implementing the "average" operation here is
activities.stream()
.mapToDouble(Activity::getEffort)
.filter(effort -> effort != Activity.NULL)
.average()
.getAsDouble();
In your case, there is a solution that is more functional - just compute the summary statistics from the stream from where you can grab the number of elements filtered and their sum:
DoubleSummaryStatistics stats =
activities.stream()
.mapToDouble(Activity::getEffort)
.filter(e -> e != Activity.NULL)
.summaryStatistics();
long effortCount = stats.getCount();
double effortSum = stats.getSum();
Is there a "best practice" strategy for modifying local variables
using the new Java 8 loops?
Don't try do to that. I think the main issues is that people try to translate their code using the new Java 8 features in an imperative way (like in your question - and then you have troubles!).
Try to see first if you can provide a solution which is functional (which is what the Stream API aim for, I believe).
I try to understand the new Java 8 Streams and I tried for days to transfer nested foreach loops over collection in Java 8 Streams.
Is it possible to refactor the following nested foreach loops including the if-conditions in Java-8-Streams?
If yes what would it look like.
ArrayList<ClassInq> Inq = new ArrayList<>();
TreeMap<String, SalesQuot> Quotations = new TreeMap<>();
ArrayList<ClassInq> tempInqAndQuot = new ArrayList<>();
ArrayList<SalesQuot> tempQuotPos = new ArrayList<>();
for(ClassInq simInq : this.Inq) {
if(!simInq.isClosed() && !simInq.isDenied()) {
for(Map.Entry<String, SalesQuot> Quot: Quotations.entrySet()) {
SalesQuot sapQuot = Quot.getValue();
if(sapQuot.getInquiryDocumentNumber().compareTo(simInq.getSapInquiryNumber()) == 0) {
simInq.setSAPQuotationNumber(sapQuot.getQuotationDocumentNumber());
tempInqAndQuot.add(simInq);
for(Map.Entry<String, SalesQuotPosition> quotp : sapQuot.getPosition().entrySet()) {
tempQuotPos.add(quotp.getValue());
}
}
}
}
}
Thanks a lot for your help.
BR
First, try to adhere to the Java naming conventions, as your upper case variable names make it really hard to read your code. Second, it’s a good thing that you want to learn about Stream API but you should not ignore the basics of the pre-Java 8 Collection APIs.
It’s not useful to iterate over an entrySet() when you are only interested in either, keys or values. You do it two times within a small piece of code.
At the first appearance you can replace
for (Map.Entry<String, SalesQuot> Quot: Quotations.entrySet()){
SalesQuot sapQuot = Quot.getValue();
with the simpler
for (SalesQuot sapQuot: Quotations.values()){
At the second, the entire
for(Map.Entry<String,SalesQuotPosition> quotp: sapQuot.getPosition().entrySet()){
tempQuotPos.add(quotp.getValue());
}
can be replaced by
tempQuotPos.addAll(sapQuot.getPosition().values());
Thus even without streams, your code can be simplified to
for (ClassInq simInq : this.Inq){
if (!simInq.isClosed() && !simInq.isDenied()){
for (SalesQuot sapQuot: Quotations.values()){
if (sapQuot.getInquiryDocumentNumber().compareTo(simInq.getSapInquiryNumber()) == 0){
simInq.setSAPQuotationNumber(sapQuot.getQuotationDocumentNumber());
tempInqAndQuot.add(simInq);
tempQuotPos.addAll(sapQuot.getPosition().values());
}
}
}
}
though it’s still not clear what it is supposed to do and whether it’s correct. Besides the errors and suspicions named in the comments to your question, modifying the incoming values (esp. from the outer loop) does not look right.
It’s also not clear why you are using ….compareTo(…)==0 rather than equals.
However, it can be straight-forwardly rewritten to use streams without changing any of the code’s logic:
this.Inq.stream().filter(simInq -> !simInq.isClosed() && !simInq.isDenied())
.forEach(simInq -> Quotations.values().stream().filter(sapQuot ->
sapQuot.getInquiryDocumentNumber().compareTo(simInq.getSapInquiryNumber())==0)
.forEach(sapQuot -> {
simInq.setSAPQuotationNumber(sapQuot.getQuotationDocumentNumber());
tempInqAndQuot.add(simInq);
tempQuotPos.addAll(sapQuot.getPosition().values());
})
);
Still, I recommend cleaning up the original logic first before rewriting it for using other APIs. The stream form would greatly benefit from a more precise definition of what to achieve.
When writing Java code, NetBeans often encourages me to convert foreach loops (with iterators) to lambda expressions. Sometimes the resulting code is much cleaner. Other times, the result is less clear than before.
For example, the following uses iterators:
List<String> list = new ArrayList<>();
for (String str : list) {
if (str.charAt(0) == ' ')) {
// do something with str
}
}
And the equivalent uses lambda expressions:
List<String> list = new ArrayList<>();
list.stream().filter((str) -> (str.charAt(0) == ' ')).forEach((str) -> {
// do something with str
)};
In this case, using lambda expressions results in lengthier code, and uses less intuitive language (stream, filter, and forEach instead of for and if). So are there any advantages to using lambdas instead of iterators, when the code isn't cleaner? For example, are there any performance gains?
Iterate over collection and doing "something" with some of it's members is not the best example for using lambdas.
Consider scenario like create result collection of objects filtered by some property, ordered by some other property and do some other "magic" and you'll see that lambdas saves dozens lines of code.
Hard to say if it's easier to read (probably not as lambda is yet another syntax you have to be familiar with) but after all - it's better to read one complex line of code instead creating anonymous/inner comparators. At least in C# lambda is very useful construction.
uses less intuitive language (stream, filter, and forEach instead of for and if
I don't really find them less intuitive. Moreover, wait for few months, those will be mostly used terms you will hear in Java. In fact, once you are comfortable with lambdas, you'll see how amazingly it cleansifies your code, that uses complex logic inside loops.
So are there any advantages to using lambdas instead of iterators, when the code isn't cleaner? For example, are there any performance gains?
One obvious advantage of streams and lambdas that comes to my mind is, it gives you the power of parallel execution more easily using Stream.parallelStream(). Also internal iteration of streams gives control of how iteration happens to the API. It can choose to evaluate intermediate operations lazily, parallely, sequentially, etc. Moreover, functional programming has it's own advantage. You can pass around logics in the form of lambdas, which used to be done using anonymous classes earlier. That way, some functionality can be easily re-used.
Although there are certain disadvantages too, when comparing with normal for loop. If your loop is modifying some local variable, then you can't get it converted to forEach and lambdas version (at least not directly), because variables used inside lambdas needs to be effectively final.
More details can be found on java.util.stream javadoc.
Just to give you some information about how I think you can write neat lambdas, is for your given code:
List<String> listString = new ArrayList<>();
for (String str : listString) {
if (str.charAt(0) == ' ') {
// do something with str
}
}
I would, convert it to the following:
List<String> listString = new ArrayList<>();
listString.stream()
.filter(s -> s.charAt(0) == ' ')
.forEach(/*do something*/);
I find the syntax like this much less intrusive and much clearer. Also, if you are going to need blocks inside your lambda, you are probably doing it wrong. Unless you have a very good reason to do so.
As an example if you would want to print every string on a new line, you could do:
List<String> listString = new ArrayList<>();
listString.stream()
.filter(s -> s.charAt(0) == ' ')
.forEach(System.out::println);
Moreover, if you need to store the data in some kind of structure, you want to be using Collectors.*, and you do not want to be doing that inside your forEach, as a silly example we would like to convert it to a List<String> again:
List<String> listString = new ArrayList<>();
List<String> filteredString = listString.stream()
.filter(s -> s.charAt(0) == ' ')
.collect(Collectors.toList());
Note that this particular implemention could have been done much easier if you were allowed to modify the original list.
With respect to performance gains, I have written a simple benchmark test for lambda expressions versus iterators. The test gives performance during warmup phase and non warmup phase. Warmup phase is considered for the first 10 iterations, non warmup phase later on. The test runs for 10k iterations and measures the average time. Below is the code:
import java.util.ArrayList;
import java.util.List;
public class LambdaTest {
private static final int COUNT = 10000;
public static void main(String[] args) {
List<String> str = new ArrayList<String>();
for (int i =0; i<100000; i++){
str.add(""+i);
}
double iterTotal = 0;
double lambdaTotal = 0;
double warmupIterTotal = 0;
double warmupLambdaTotal = 0;
for(int j = 0; j < COUNT; j++){
long start = System.nanoTime();
for (int i = 0; i< 100000; i++){
String string = str.get(i);
// if(string.length() < 5){
// System.out.println(string);
// }
}
long end = System.nanoTime();
if(j>=10){
iterTotal += end - start;
}else {
warmupIterTotal += end - start;
}
System.out.println("Output 1 in : "+(end-start)*1.0/1000 +" Us");
start = System.nanoTime();
str.forEach((string) -> {
// if(string.length() < 5){
// System.out.println(string);
// }
});
end = System.nanoTime();
if(j>=10){
lambdaTotal+= end-start;
}else {
warmupLambdaTotal += end - start;
}
System.out.println("Output 2 in : "+(end-start)*1.0/1000 +" Us");
}
System.out.println("Avg Us during warmup using Iter: "+warmupIterTotal/(1000*10));
System.out.println("Avg Us during warmup using Lambda: "+warmupLambdaTotal/(1000*10));
System.out.println("Avg Us using Iter: "+iterTotal/(1000*(COUNT-10)));
System.out.println("Avg Us using Lambda: "+lambdaTotal/(1000*(COUNT-10)));
}
}
The output of the above code is as below:
Avg Us during warmup using Iter: 1372.8821
Avg Us during warmup using Lambda: 5211.7064
Avg Us using Iter: 373.6436173173173
Avg Us using Lambda: 370.77465015015014
Thus, as we can see the lambda expressions perform poorly in the warmup stages but post-warmup the performance with lambda expressions is quite similar to iterators. This is just a simple test and if you are trying out a complex expression in your application, you can better profile the application and check which one works better in your case.
What are the most common mistakes that Java developers make when migrating to Scala?
By mistakes I mean writing a code that does not conform to Scala spirit, for example using loops when map-like functions are more appropriate, excessive use of exceptions etc.
EDIT: one more is using own getters/setters instead of methods kindly generated by Scala
It's quite simple: Java programmer will tend to write imperative style code, whereas a more Scala-like approach would involve a functional style.
That is what Bill Venners illustrated back in December 2008 in his post "How Scala Changed My Programming Style".
That is why there is a collection of articles about "Scala for Java Refugees".
That is how some of the SO questions about Scala are formulated: "help rewriting in functional style".
One obvious one is to not take advantage of the nested scoping that scala allows, plus the delaying of side-effects (or realising that everything in scala is an expression):
public InputStream foo(int i) {
final String s = String.valueOf(i);
boolean b = s.length() > 3;
File dir;
if (b) {
dir = new File("C:/tmp");
} else {
dir = new File("/tmp");
}
if (!dir.exists()) dir.mkdirs();
return new FileInputStream(new File(dir, "hello.txt"));
}
Could be converted as:
def foo(i : Int) : InputStream = {
val s = i.toString
val b = s.length > 3
val dir =
if (b) {
new File("C:/tmp")
} else {
new File("/tmp")
}
if (!dir.exists) dir.mkdirs()
new FileInputStream(new File(dir, "hello.txt"))
}
But this can be improved upon a lot. It could be:
def foo(i : Int) = {
def dir = {
def ensuring(d : File) = { if (!d.exists) require(d.mkdirs); d }
def b = {
def s = i.toString
s.length > 3
}
ensuring(new File(if (b) "C:/tmp" else "/tmp"));
}
new FileInputStream(dir, "hello.txt")
}
The latter example does not "export" any variable beyond the scope which it is needed. In fact, it does not declare any variables at all. This means it is easier to refactor later. Of course, this approach does lead to hugely bloated class files!
A couple of my favourites:
It took me a while to realise how truly useful Option is. A common mistake carried from Java is to use null to represent a field/variable that sometimes does not have a value. Recognise that you can use 'map' and 'foreach' on Option to write safer code.
Learn how to use 'map', 'foreach', 'dropWhile', 'foldLeft', ... and other handy methods on Scala collections to save writing the kind of loop constructions you see everywhere in Java, which I now perceive as verbose, clumsy, and harder to read.
A common mistake is to go wild and overuse a feature not present in Java once you "grokked" it. E.g. newbies tend to overuse pattern matching(*), explicit recursion, implicit conversions, (pseudo-) operator overloading and so on. Another mistake is to misuse features that look superficially similar in Java (but ain't), like for-comprehensions or even if (which works more like Java's ternary operator ?:).
(*) There is a great cheat sheet for pattern matching on Option: http://blog.tmorris.net/scalaoption-cheat-sheet/
I haven't adopted lazy vals and streams so far.
In the beginning, a common error (which the compiler finds) is to forget the semicolon in a for:
for (a <- al;
b <- bl
if (a < b)) // ...
and where to place the yield:
for (a <- al) yield {
val x = foo (a).map (b).filter (c)
if (x.cond ()) 9 else 14
}
instead of
for (a <- al) {
val x = foo (a).map (b).filter (c)
if (x.cond ()) yield 9 else yield 14 // why don't ya yield!
}
and forgetting the equals sign for a method:
def yoyo (aka : Aka) : Zirp { // ups!
aka.floskel ("foo")
}
Using if statements. You can usually refactor the code to use if-expressions or by using filter.
Using too many vars instead of vals.
Instead of loops, like others have said, use the list comprehension functions like map, filter, foldLeft, etc. If there isn't one available that you need (look carefully there should be something you can use), use tail recursion.
Instead of setters, I keep the spirit of functional programming and have my objects immutable. So instead I do something like this where I return a new object:
class MyClass(val x: Int) {
def setX(newx: Int) = new MyClass(newx)
}
I try to work with lists as much as possible. Also, to generate lists, instead of using a loop, use the for/yield expressions.
Using Arrays.
This is basic stuff and easily spotted and fixed, but will slow you down initially when it bites your ass.
Scala has an Array object, while in Java this is a built in artifact. This means that initialising and accessing elements of the array in Scala are actually method calls:
//Java
//Initialise
String [] javaArr = {"a", "b"};
//Access
String blah1 = javaArr[1]; //blah1 contains "b"
//Scala
//Initialise
val scalaArr = Array("c", "d") //Note this is a method call against the Array Singleton
//Access
val blah2 = scalaArr(1) //blah2 contains "d"