Java Streams Preview vs .Net High-Order Programming with LINQ

Edwin DalorzoIn today’s post I want to share with you a comparison that I did this weekend between the high-order programming features from LINQ and those being incorporated into the new Java 8 streams API.  It is important to highlight that the Java Stream API is still work in progress. I have been downloading and building the source code of Project Lambda for almost a year now and I have seen how the API evolves over time, but the improvements are more frequent as we approach the general availability date (planed for September 2013).

Before I delve into the comparisons, I must say that as of today, the current implementation of the Java Stream API is far away from all the high-order programming functionality offered by LINQ. It has already been announced in the mailing list that there was not going to be enough time for all improvements originally planned and the JEP 108: Collection Enhancements for Third-party Libraries has been deferred to future releases of Java. I am not sure how much of the Stream API is going to be affected by this decision but I hope that in the remaining months, prior to the release, they do much more improvements in the current API, at least, bring it closer to LINQ.

At any rate, as of today, it appears that some basic functionality is already covered (filter, map, reduce, sort, etc.), but much more work is still needed for this API to be decently compared to LINQ in terms of functionality and my comparison here only focuses particularly in the high-order programming features. So, I really hope that it is only too early to write this article, and in the coming months things are going to improve dramatically.

Also, there are some inherent problems that have been evidently difficult to overcome. One of those affecting the design of the API is the lack of value types in Java. It appears that the expert group have been struggling with this, and their solution has been to make copies of some interfaces, defining some to deal with primitive types (i.e. IntStream, LongStream, DoubleStream) and others with reference types (i.e. Stream). This has also caused a diaspora of copies of other functional interfaces (aka interface polution), particularly in the case of the interface Function the problem is much more evident (i.e. ToIntFunction, ToLongFunction, ToDoubleFunction and Function).

Even when all this repetition is done to alleviate the performance problems inherent to boxing and unboxing of primitive types, this workaround has undesirable side effects: first, the need to overload methods for everyone of these interfaces. This overloading is undesirable because it makes it impossible to use a clean lambda expression for these cases, since the compiler is incapable to determine which of all the argument functional interfaces is the one being implemented by the lambda. So, to avoid compiler errors we are  forced to use awful type castings in the code, which make it more verbose and look pretty bad. And a secondary side effect is the incompatibility between primitive type and reference type collections (i.e. an Stream<Integer> is not the same as an IntStream).

About the Comparison

For this exercise I took the code examples from the book .Net 4.0 Generics a Beginners Guide by Sudipta Mukherjee, particularly his examples from Chapter 4: LINQ to Objects. I did not do all the examples simply because there are many features still lacking in the Java Stream API which make it impossible to replicate the same functionality.

The author of the book makes all these examples to demonstrate LINQ high-order programming functionality. It is not  my intention to write an article on LINQ and all it can do, but a comparison of what I could do with the high-order programming features in the Stream API today if I wanted to implement similar idioms as those I can so easily implement using LINQ functionality. Perhaps I may have misinterpreted the author in his use of all these examples to illustrate LINQ, or perhaps, the author only intended to illustrate just one aspect of this broad technology. Therefore, this article is  based on my understanding of his view of this part of LINQ in order to make a comparison, but I can understand that LINQ is more than just a bunch of high-order functions.

Now some may argue that there is no intention in making the stream API something comparable to LINQ, which may well be true, but still LINQ offers a good example of an API that makes extensive use of high-order programming to query collections, and even if the stream API is not yet intended to query things like XML or SQL (at least initially/yet), I feel that it is still a good benchmark to compare the power of expressiveness in this new Java API. For me, this gives me an idea of how evolved this API is today when compared to the power of expressiveness of this another state-of-art technology. As it is customary in the internet world, others may freely disagree with me and present their personal perspectives as I did here.

For the cases that I could implement, the examples are based on the use of Stream and IntStream classes, and the static methods available on the Streams and Collectors helper classes. In order to keep it simple and readable I am not showing in the code examples below all the imports and static imports that  I used. For that matter you may want to take a look at the following Gist where I have published most of these examples and where you will be able to see full imports needed to make the code run properly.

Restriction Operators

Challenge 1: Filtering

Say we have a List of names and we would like to find all those names where "am" occurs:


LINQ

string[] names = { "Sam", "Pamela", "Dave", "Pascal", "Erik" };
List<string> filteredNames = names.Where(c => c.Contains("am"))
                                  .ToList();

Java Streams

String[] names = {"Sam","Pamela", "Dave", "Pascal", "Erik"};
List<String> filteredNames = stream(names)
			     .filter(c -> c.contains("am"))
			     .collect(toList());

Challenge 2: Indexed Filtering

Find all the names in the array "names" where the length of the name is less than or equal to the index of the element + 1.


LINQ

string[] names = { "Sam", "Pamela", "Dave", "Pascal", "Erik" };
var nameList = names.Where((c, index) => c.Length <= index + 1).ToList();

Java Streams

Now this one was particularly tricky in Java because, as of today, the API for streams does not contain any methods that indicate the index of an element within the stream. So, I was forced to generate an indexed stream out of the original array:

String[] names = {"Sam","Pamela", "Dave", "Pascal", "Erik"};

List<String> nameList;
Stream<Integer> indices = intRange(1, names.length).boxed();
nameList = zip(indices, stream(names), SimpleEntry::new)
			.filter(e -> e.getValue().length() <= e.getKey())
			.map(Entry::getValue)
			.collect(toList());

Now, the lack of indices in the stream made the algorithm more verbose, but it was also interesting to notice the incompatibilities between primitive-type streams, like IntStream and reference type streams like Stream<Integer>. In this case, I was forced to transform the IntStream returned by intRange into a Stream<Integer> in order to make the argument compatible with the types expected by zip as you can see in the line #4.


Projection Operators

Challenge 3: Selecting/Mapping

Say we have a list of names and we would like to print “Hello” in front of all the names:


 LINQ

List<string> nameList1 = new List(){ "Anders", "David", "James",
                                     "Jeff", "Joe", "Erik" };
nameList1.Select(c => "Hello! " + c).ToList()
         .ForEach(c => Console.WriteLine(c));

Java Streams

List<String> nameList1 = asList("Anders", "David", "James",
                                "Jeff", "Joe", "Erik");
nameList1.stream()
	 .map(c -> "Hello! " + c)
	 .forEach(System.out::println);

Challenge 4: Selecting Many/Flattening

Suppose, we have a dictionary such that each key has a list of values attached to them. Now, we want to project all the elements in a single collection:


LINQ

Dictionary<string, List<string>> map = new Dictionary<string,List<string>>();
map.Add("UK", new List<string>() {"Bermingham", "Bradford", "Liverpool"});
map.Add("USA", new List<string>() {"NYC", "New Jersey", "Boston", "Buffalo"});
var cities = map.SelectMany(c => c.Value).ToList();

Java Streams

Once more, the Java syntax, as of today, is a bit more verbose. First, we must transform the map to an entry set, and from there, we can generate a stream that we can later flatten to a list of cities, as follows:

Map<String, List<String>> map = new LinkedHashMap<>();
map.put("UK", asList("Bermingham","Bradford","Liverpool"));
map.put("USA", asList("NYC","New Jersey","Boston","Buffalo"));

FlatMapper<Entry<String, List<String>>,String> flattener;
flattener = (entry,consumer) -> { entry.getValue().forEach(consumer); };

List<String> cities = map.entrySet()
			 .stream()
			 .flatMap( flattener )
			 .collect(toList());

Ideally the lines 5, 6 should be defined as inline arguments of flatMap, but the compiler cannot properly infer the types of the expression precisely for the overloading problems that I described above. Given the amount of type information that must be provided, I felt that it was best to define it in another line as I did in #5 and #6. It looks awful,  I know. Clearly, we are in desperate need of an API that offers operations to deal with maps or tuples.


Partitioning Operators

Challenge 5: Taking an Arbitrary Number of Items

In this case we are interested in evaluating only the first n elements of a collection. For instance, using a finite list of numbers, obtain the first 4 of them.


LINQ

int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
var first4 = numbers.Take(4).ToList();

Java Streams

Once more, in Java, the absence of value types forced me to make a conversion from an IntStream into a Stream<Integer> to make this work (see line #5), basically because there is not value type collector. An alternative would have been to consume the stream itself (i.e. forEach) or to collect items into an array using Stream.toArray() method.

int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,13 };

List<Integer> firstFour;
firstFour = stream(numbers).limit(4)
                           .boxed()
                           .collect(toList());

Challenge 6: Taking Items Based on Predicate

In this case we are interested in taking items out of a collection as long as they satisfy a predicate. Once we find an item that does not satisfy the predicate we stop there.


LINQ

string[] moreNames = { "Sam", "Samuel", "Dave", "Pascal", "Erik",  "Sid" };
var sNames = moreNames.TakeWhile(c => c.StartsWith("S"));

Java Streams

As of today, there is no way to implement this idiom in Java using the streams API. There is an alternative way to do this, but it is not the same thing. The beauty of takeWhile is that is should be short-circuited, that is, it should stop the evaluation in the moment that one item does not satisfies the predicate. The following version in Java does not have this property:

String[] names  = { "Sam","Samuel","Dave","Pascal","Erik","Sid" };

List<String> found;
found = stream(names).collect(partitioningBy( c -> c.startsWith("S")))
                     .get(true);

The collector created by partitioningBy (line #4) forces the evaluation of the whole stream, placing items into a boolean map, where all items that satisfy the predicate are bound to true and all others to false. So clearly, it is not the same thing. I hope that as the Oracle expert group works on the API they fix this omission.


Challenge 7: Skipping an Arbitrary Number of Items

In this case we are interested in skipping items in a collection up to certain arbitrary number, then we keep the rest of the items.


LINQ

string[] vipNames = { "Sam", "Samuel", "Samu", "Remo", "Arnold","Terry" };
var skippedList = vipNames.Skip(3).ToList();//Leaving the first 3.

Java Streams

In Java, the solution consists in creating a new stream where the first n elements have been discarded. As follows:

String[] vipNames = { "Sam", "Samuel", "Samu", "Remo", "Arnold","Terry" };

List<String> skippedList;
skippedList = stream(vipNames).substream(3).collect(toList());

Challenge 8: Skipping Items Based on Predicate

In this case we are interested in skipping items out of a collection as long as they satisfy a predicate. Once we find an item that does not satisfy the predicate we take the rest of the items from there.


LINQ

int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 20 };
var skippedList = numbers.SkipWhile(c => c < 10);

Java Streams

With current streams API I found no way to implement this idiom.

Ordering Operators

Challenge 9: Ordering/Sorting Elements

Order the elements of a collection alphabetically:


LINQ

string[] friends = { "Sam", "Pamela", "Dave", "Anders", "Erik" };
friends = friends.OrderBy(c => c).ToArray();

Java Streams

In the case of Java, we use the sorted method to produce the same result. The sorted method can also accept a Comparator to determine the sorting criteria.

String[] friends = { "Sam", "Pamela", "Dave", "Anders", "Erik" };
friends = stream(friends).sorted().toArray(String[]::new);

Challenge 10: Ordering/Sorting Elements by Specific Criterium

Order the elements of a collection strings according to the length of the string:


LINQ

string[] friends = { "Sam", "Pamela", "Dave", "Anders", "Erik" };
friends = friends.OrderBy(c => c.Length).ToArray();

Java Streams

In this case we pass a Comparator to the sort method. And once again, we hit against the problem of overloaded methods defined in the API to deal with the lack of value types in Java. Here we are forced to provide an explicit casting (line #3) to help the compiler:

String[] friends = { "Sam", "Pamela", "Dave", "Anders", "Erik" };
friends = stream(friends)
           .sorted(comparing((ToIntFunction<String>)String::length))
           .toArray(String[]::new);

An alternative way could be to provide an implementation of the Comparator (line #3), in this case, by means of a binary lambda expression. This is a little cleaner, but more verbose.

String[] friends = { "Sam", "Pamela", "Dave", "Anders", "Erik" };
friends = stream(friends)
            .sorted( (s1,s2) -> Integer.compare(s1.length(), s2.length()))
            .toArray(String[]::new);

Challenge 11: Ordering/Sorting Elements by Multiple Criteria

Order the elements of a collection of strings according to several sorting criteria:


LINQ

string[] fruits = {"grape", "passionfruit", "banana",
                   "apple", "orange", "raspberry",
                   "mango", "blueberry" };

//Sort the strings first by their length and then alphabetically.
//preserving the first order.
var sortedFruits = fruits.OrderBy(fruit =>fruit.Length)
                         .ThenBy(fruit => fruit);

Java Streams

Originally I had thought it was not possible to implement this idiom with the latest release of the API, but one of our readers had a good suggestion. Even so I was not able to get rid of the castings in lines #5 and #7. Once again the interface pollution causes the need for castings to clarify which of the overloaded methods are the ones being implemented in Comparators and Comparator here.

String[] fruits = {"grape", "passionfruit", "banana","apple",
                   "orange", "raspberry","mango", "blueberry" };

Comparator<String> comparator;
comparator = comparing((Function<String,Integer>)String::length,
                       Integer::compare)
            .thenComparing((Comparator<String>)String::compareTo);

fruits = stream(fruits) .sorted(comparator)
                        .toArray(String[]::new);

Grouping Operators

Challenge 12: Grouping by a Criterium

Group the elements of a collection of strings by their length.


LINQ

string[] names = {"Sam", "Samuel", "Samu", "Ravi", "Ratna",  "Barsha"};
var groups = names.GroupBy(c => c.Length);

Java Streams

String[] names = {"Sam", "Samuel", "Samu", "Ravi", "Ratna",  "Barsha"};

Map<Integer,List<String>> groups;
groups = stream(names).collect(groupingBy(String::length));

Set Operators

The current implementation of streams is way behind LINQ in this area. From all possible set operations, the only ones currently implemented are “distinct” and “concat”, although “concat” is not a set operation because it would accept duplicates, the correct would be to have a “union” operation, but this does not exist in the stream API yet.

Challenge 13: Filter Distinct Elements

Obtain all the distinct elements from a collection.


LINQ

string[] songIds = {"Song#1", "Song#2", "Song#2", "Song#2", "Song#3", "Song#1"};
//This will work as strings implement IComparable
var uniqueSongIds = songIds.Distinct();

Java Streams

String[] songIds = {"Song#1", "Song#2", "Song#2", "Song#2", "Song#3", "Song#1"};
//according to Object.equals
stream(songIds).distinct();

Challenge 14: Union of Two Sets

Join together two sets of items.


LINQ

List<string> friends1 = new List<string>() {"Anders", "David","James",
                                            "Jeff", "Joe", "Erik"};
List<string> friends2 = new List<string>() { "Erik", "David", "Derik" };
var allMyFriends = friends1.Union(friends2);

Java Streams

In Java we have to concatenate the two streams and then obtain the distinct elements.

List<String> friends1 = asList("Anders","David","James","Jeff","Joe","Erik");
List<String> friends2 = asList("Erik","David","Derik");
Stream<String> allMyFriends = concat(friends1.stream(),
                                     friends2.stream()).distinct();

Element Operatos

Challenge 15: First Element

Obtain the first element of a collection.


LINQ

string[] otherFriends = {"Sam", "Danny", "Jeff", "Erik", "Anders","Derik"};
string firstName = otherFriends.First();
string firstNameConditional = otherFriends.First(c => c.Length == 5);

Java Streams

In Java we use the findFirst method which returns an Option object. The object may contain something or nothing, to validate that one must invoke the isPresent method on the returned object.

String[] otherFriends = {"Sam", "Danny", "Jeff", "Erik", "Anders","Derik"};
Optional<String> found = stream(otherFriends).findFirst();

Optional<String> maybe = stream(otherFriends).filter(c -> c.length() == 5)
                                             .findFirst();
if(maybe.isPresent()) {
   //do something with found data
}

Range Operators

Challenge 16: Generate a Range of Numbers

Generate a range of numbers that are multiples of 11.


LINQ

var multiplesOfEleven = Enumerable.Range(1, 100).Where(c => c % 11 == 0);

Java Streams

IntStream multiplesOfEleven = intRange(1,100).filter(n -> n % 11 == 0);

Quantifier Operators

Challenge 17: All

Do all elements in a collection satisfy a predicate?


LINQ

string[] persons = {"Sam", "Danny", "Jeff", "Erik", "Anders","Derik"};
bool x = persons.All(c => c.Length == 5);

Java Streams

String[] persons = {"Sam", "Danny", "Jeff", "Erik", "Anders","Derik"};
boolean x = stream(persons).allMatch(c -> c.length() == 5);

Challenge 18: Any

Do any elements in a collection satisfy a predicate?


LINQ

string[] persons = {"Sam", "Danny", "Jeff", "Erik", "Anders","Derik"};
bool x = persons.Any(c => c.Length == 5);

Java Streams

String[] persons = {"Sam", "Danny", "Jeff", "Erik", "Anders","Derik"};
boolean x = stream(persons).anyMatch(c -> c.length() == 5);

Merging Operators

Challenge 19: Zip

Combine two collections into a single collection.


LINQ

string[] salutations = {"Mr.", "Mrs.", "Ms", "Master"};
string[] firstNames = {"Samuel", "Jenny", "Joyace", "Sam"};
string lastName = "McEnzie";

salutations.Zip(firstNames, (sal, first) => sal + " " + first)
           .ToList()
           .ForEach(c => Console.WriteLine(c + " " + lastName));

Java Streams

String[] salutations = {"Mr.", "Mrs.", "Ms", "Master"};
String[] firstNames = {"Samuel", "Jenny", "Joyace", "Sam"};
String lastName = "McEnzie";

zip(
    stream(salutations),
    stream(firstNames),
    (sal,first) -> sal + " " +first)
.forEach(c -> { System.out.println(c + " " + lastName); });

In general, things are still not looking good, but I really hope that will change in the coming months. There are challenges that will be difficult to overcome, like the issues with value types, but in my opinion we could  live with those problems as long as we are provided with an API sufficiently expressive.

I am currently working on another set of examples in which I work on a small data model and see what I can do with it to run all kinds of queries using the Stream API, but I will leave that for my next post.

Related Posts

Further Reading

About these ads

37 thoughts on “Java Streams Preview vs .Net High-Order Programming with LINQ

  1. Pingback: Java Streams API Preview | Informatech CR Blog

  2. Wow! Way to go, Oracle. The API looks great as far as I’ve seen. Of course there are some features missing, but looks like is heading the right way.

    One good thing about this is that now more C# and functional developers will find appealing to work in Java and I think that’s a great since it will widen its fan-base.

  3. Hi,
    It is a very nice comparison – good job. Some minor improvements are still possible. E.g. Challenge 10 can be written as (using current build b82):

    friends = stream(friends)
    .sorted(Comparators.comparing(String::length, Integer::compare))
    .toArray(String[]::new);

    Then Challenge 11 is perfectly doable:

    friends = stream(friends)
    .sorted(Comparators.comparing(String::length, Integer::compare)
    .thenComparing(String::compareTo))
    .toArray(String[]::new);

    • HI and thanks for dropping by and leaving your comments. You are totally right, I had not seen the thenComparing method in Comparator. I will update the article with your solution.This is great.

    • This is great, thanks for sharing the link. I have also experimented a bit with the implementation of this idioms using my own code. I can see your point that it must be difficult to implement from the standpoint of the parallel APIs, however, I still think it needs to be added somehow to the API, perhaps in the form of a collector. This is a common high-order function in most functional languages and not having it in the Java API would be a painful omission. Don’t you think?

  4. Pingback: Java Infinite Streams | Informatech CR Blog

  5. Why do you refer to extension methods for collections as LINQ? This is quite misleading and can give false picture that Streams API is something similar to Language Integrated Queries.

    • Thanks for dropping by and leave your comments. As the article says, the examples are based on the book .Net 4.0 Generics, under the chapter 4: LINQ to Objects. So, the author of the book (Sudipta Mukherjee) makes all these examples to demonstrate LINQ functionality. It was never my intention to write an article on LINQ and all it can do, but a comparison of what I could do with the Stream API if I wanted to implement similar idioms. It is likely that your comment refers to my lack of a broader understanding of what LINQ actually means and it has to offer, which wouldn’t be surprise for me given the fact that I have little experience with LINQ itself. That’s why I based my comparisons in the examples provided by the book cited above. Perhaps I may have misinterpreted the author in his use of all these examples to illustrate LINQ, or perhaps, the author only intended to illustrate just one aspect of this broad technology. I based my article on this view to make a comparison.

      Now, you may also be referring to the point that there is no intention in making the stream API something comparable to LINQ, which is true. But still LINQ offers a good example of an API that makes extensive use of high-order programming to query collections, and even if the stream API is not yet intended to query things like XML or SQL, I feel that it is still a good benchmark to compare the power of expressiveness in the API. Wouldn’t you agree?

  6. I was wondering why you have the ToList() on many of the C# examples. One of the nice features of LINQ is the lazy evaluation of the expressions. Using ToList() will actually materialize a new collection with the evaluated result. Leaving out the ToList() will only materialize the elements as they are iterated.

    This provide a kind og infinitive collections, where processing millions and millions of collection elements – like rows from a database or lines from log files can be done with quite limited memory consumption.

    It can also have quite positive performance significance. If you have a collection (list or db set) and you will break out as soon as you find the first element that match a specified predicate, then you only have to parse elements until the one found and not have to deal with the remaining elements in the collection.

    • That’s right, Anders. Actually that’s what makes LINQ so powerful: Lazy evaluation. It is already noticeable how it improves processing times on collections, but its true power is shown when it comes to database rows, by using LINQ to SQL you can build up a SQL query the same you would query a collection and then execute it as soon as ToList() is called letting LINQ to internally generate the best SQL query based in your expression and execute it at the database.

    • Likewise in the case of Java streams, the stream is not evaluated until a terminal operation is found. As you well point out, the collect method is a terminal operation. I can only assume the method ToList() is also a terminal operation in the LINQ example, since it has to generate the list containing the items.

  7. I am suprise but some of your challenge. E.g. Ordering/Sorting Elements by Specific Criterium

    How to you do when the stream is infinite? May be it is a difference between java and linq?

    • You could not sort an infinite stream, simply because it is infinite. But you can transform an infinite stream into a finite stream. For instance, assuming that nats is a infinite stream of natural numbers, you could do something like

      nats.takeWhile(n -> n < 100).sort()

      In this case, the takeWhile method should allow us to transform the infinite stream of natural numbers into a finite stream containing a discrete number of elements, in this case, all those smaller than 100. That finite stream we could sort.

      The basic problem with the API today is that we do not have a method takeWhile.

  8. Adding more to the details of the LINQ (have to say I’m not at all familiar with the Java stream functionality), but as most LINQ functions are utilizing the IEnumeable interface, the .NET extension methods allows one to extend the default set of LINQ operations with custom ones.

    That is something, when used with care, really make code much more readable and a lot easier to maintain.

    public static class Extension
    {
    public static void Dump(this IEnumerable self, Predicate p)
    {
    foreach( var element in self.Where( p => p)
    {
    Console.WriteLine( element.ToString());
    }
    }
    }

    Used in this way:

    collection.Dump( p => p.Name.Contains(“e”));

    • That is true. The power of extension methods here is that anyone, at anytime can define new methods for an existing class. In Java 8 we’ll have something called “default methods” which will allow the “designers” of an interface to add default implementations to interface methods, by this opening a door to evolve interfaces. Although this feature is not the same as the extension methods from .Net, it has allowed the addition of a few new methods to preexisting collection interfaces. One of those methods is the forEach method. What you wrote in your comment can be achieved by doing:

      collection.stream()
      .filter(p -> p.getName().contains("e"))
      .forEach(System.out::println);

      Or if I wanted to consume all items from a collection (without filtering), I could simply do:

      collection.forEach(System.out::println);

      So, even when you cannot define new “extension” methods for the collection, you may define as many new consumers as you want, for instance:

      collection.forEach(MyNetworkSocket::send);

  9. The Scala examples looks nice and very compact. I know it is a matter of taste and what one is used to, but I think that most of the LINQ examples are more readable, even for someone who not normally write this type of code. The Scala examples seems a bit more complex as The language syntax, don’t seem so clean and consistent as LINQ.

    On the other hand .Net actually provide two implementations of LINQ, the one shown here the method syntax and the query syntax, which look a lot like SQL syntax.

    var results = from element in list
    where item.zip == 3600
    select item;

    Is the same as

    var results = list.Where( item => item.zip == 3600);

    Depending on the complexity of the LINQ expressions, it is actually sometime beneficial to use the query syntax.

  10. Pingback: Parallel Looping Constructs in Java (revisited) « Blogging at the speed of thought

  11. Wow! program in LINQ is very short and less complex as compare to Java in all challenges which you shown here. But programmers who haven’t in depth knowledge prefers Java as it’s API is easily available on web for copy-paste.

  12. Pingback: 10 Common Mistakes Java Developers Make when Writing SQL | Java, SQL, and jOOQ / jOOX

  13. Pingback: Java语言开发之SQL语句改善

  14. Pingback: 10 Subtle Best Practices when Coding Java | Java, SQL, and jOOQ / jOOX

  15. Pingback: Super Vergleich von Java 8 Streams und .NET LINQ - Java Blog | Javainsel-Blog

  16. Why did you choose to show all the C# examples with explicit typing? Most C# devs these days use type inference with var to save on boilerplate repetition.

    But a nice post, albeit a large part of LINQ i.e. IQueryable is absent from here. As well as the extensible nature of extension methods.

    • Hey Isaac. Thanks for leaving your comment.

      I am not so verse in C# as I wish, Isaac. That’s why it is probable that my C# examples are not that good. Also at the beginning of the post I explain that I simply replicate the examples of the book .Net 4.0 Generics a Beginners Guide by Sudipta Mukherjee. I wanted to focus on the power of expressivity of the API more than just in syntactical differences.

  17. Firstly you have to update your post, there are more news in final release of Java 8.
    There no boxed() method, there is skip(n) method, we don’t need to make substream,
    You can just do :
    For challenge 8,if items are ordered then we can do with Linq:
    int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 20 };
    var skippedList = numbers.SkipWhile(c => c < 10);
    I don't see difference with this code in Java
    int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 20 };
    List
    skippedList = stream(numbers).filter(c->c>=10
    .collect(toList());
    I don’t have time to read every challenges now

    • @bilalsoidik, thanks for dropping by and comment. I have not updated my post because I am no longer an author in this blog. Although I still comment on my posts from the past. It is true, this examples are based on an edition of the JDK 8 before it even went into Beta. I started building the source code long before there were available releases, and some of these examples are based on the API on those days.

      Regarding your comment about SkipWhile. There is a very fundamental difference between SkipWhile and Collect. The main difference is that collect is a terminal method, and therefore causes the evaluation of the whole stream, whereas SkipWhile is a lazy method.

      • You should understand the difference between lazy evaluation eager evaluation, and terminal method and intermediate method, both concepts have large differences. All stream methods are lazy, because it is the stream who is lazy not the method. Who told you that terminal method means eager evaluation? When we say that this method is terminal method that doesn’t mean it eager evaluated, no. We wont to say that it is the method who will make the stream consumed, the method who will produce the result and all operations will be triggered and evaluated lazily. If there is no terminal method now thing will be produced.
        Take the example:
        When we do,

        myStream.map(m->m*3)
        .filter(s->s%2==0)
        .forEach(out::println)

        Yes, forEach is terminal method, but this never means that map and filter will work lazily and when they finished working that that forEach will start to work, never. We don't have this series
        map->filter; map->filter; map->filter... and then forEach=> out::println->out::println->out::println NO NO!!
        We have,

        forEach==> map->filter->out::println (if is filtered),map->filter->out::println (if is filtered),map->filter->out::println (if is filtered).....

        And when we have,

        List list= myStream.map(m->m*3)
        .filter(s->s%2==0)
        .collect(toList())

        We have this series,
        collect==> map->filter->toList()(if is filtered),map->filter->toList() (if is filtered),map->filter->toList() (if is filtered)....
        We can do the same thing what dose collect without using the collect method, we can do,

        List list =new ArrayList()
        myStream.map(m->m*3)
        .filter(s->s%2==0)
        .forEach(v->list.add(f))

        It is the same thing, jut collect make the work easy.
        If you want to see the correct way that terminal methods are works, use the peak method which takes a consumer and works like forEach but it is intermediate method.
        Take this code,

        int[] numbers = { 1, 2, 3, 4, 5, 6};
        stream(numbers).map(m->2*m)
        .peak(out::println)
        .filter(c->c%3)
        .peak(out::println)
        .forEach(out::println)

        That will produce,
        2
        ---
        4
        ---
        6
        6
        6
        ---
        8
        ---
        10
        ---
        12
        12
        12
        But if you do,

        stream(numbers).map(m->2*m)
        .peak(out::println)
        .filter(c->c%3)
        .peak(out::println)

        Nothing will happen. The same principle works with the method. So that what means streams are lazy. I invite you to read JavaDoc, It is written nowhere that the terminal operation are not evaluated lazily

        http://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html

        If you want to tell me that the SkipWhile() in linq works like intermediate method, so it's weird'. Because, when I do var skippedList = numbers.SkipWhile(c => c c c % 2 == 0), that means two things skippedList it is not a list but, some thing like stream who doesn't have data, the same way if we do
        IntStream stream=stream(numbers).map(m->2*m)
        .filter(c->c%3)
        no thing is produced, just you are saving operations, but if skippedList has data, there no lazy evaluation in this case.
        Because, if we do numbers.SkipWhile(c => c c % 2 == 0), SkipWhile() will finish his working and then pass to Where.
        So, if skeppedList is like stream, then, that sample we can write is IntStream skippedList = stream(numbers).filter(c->c>=10)
        The time that we will need to print ou store in a list we can do skippedList.forEach(...)

  18. Pingback: Java 8 Friday: Language Design is Subtle | Java, SQL and jOOQ.

  19. Pingback: Java 8 Friday: The Best Java 8 Resources – Your Weekend is Booked | Java, SQL and jOOQ.

  20. Pingback: Does Java 8 still need LINQ? Or is it better than LINQ? - JAXenter

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s