Wednesday, April 10, 2013

Java Streams vs C# LINQ vs Java6

A while back I ran into an article comparing C# LINQ to the upcoming Java8 Streams API: http://blog.informatech.cr/2013/03/24/java-streams-preview-vs-net-linq/.

I'm not really experienced with C# but I have a feeling that the language as a whole is quite verbose and, well, bad? Except for LINQ which performs magic with monadic comprehension.

I've been coding in Java for the most of my career, so I know a thing or two about it:
  1. it's really verbose.
  2. it's really, really, verbose.
  3. it's not nearly as verbose as you think. It's often just bad practice and inferior style that makes it so verbose and incomprehensible.
Since Java is still the language of my enterprise-day-job, I decided to ease my pain a bit, so I implemented my own functional utility library. I got a bit carried away, so I ended up with some annotation processors to bring something like poor-mans-first-class-functions into Java.

Since the library often provides rather clean ways to express ones intent, I wanted to see how it would compare to LINQ and Java Streams. So here it goes, examples from the Informatech blog supplemented with examples using plain old Java6 (released in 2007) using my functional library with annotation processors.

#Edit: I have written a follow-up with updated examples.

Challenge 1: Filtering


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());

Java6

String[] names = { "Sam", "Pamela", "Dave", "Pascal", "Erik" };
List<string> filteredNames = newList(filter(names, contains("am")));

Challenge 2: Indexed Filtering


LINQ

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

Java Streams

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());

Java6

String[] names = { "Sam", "Pamela", "Dave", "Pascal", "Erik" };
List<String> nameList = newList(map(filter(zipWithIndex(names), pred),
                                    Transformers.<String> right()));

static boolean pred(Map.Entry<Integer, String> candidate) {
    return candidate.getValue().length() <= candidate.getKey() + 1;
}

Challenge 3: Selecting/Mapping


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);

Java6

List<String> nameList1 = newList("Anders", "David", "James", "Jeff", "Joe", "Erik");
foreach(map(nameList1, prepend("Hello! ")),
            PrintStream_.println8.apply(System.out));

Challenge 4: Selecting Many/Flattening


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

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());

Java6

Map<String, List<String>> map = newMap(
    Pair.of("UK", newList("Bermingham", "Bradford", "Liverpool")),
    Pair.of("USA", newList("NYC", "New Jersey", "Boston", "Buffalo")));
List<String> cities = newList(flatten(map.values()));

Challenge 5: Taking an Arbitrary Number of Items


LINQ

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

Java Streams

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());

Java6

int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
List<Integer> firstFour = newList(take(newArray(numbers), 4));



Challenge 6: Taking Items Based on Predicate


LINQ

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

Java Streams

String[] names  = { "Sam","Samuel","Dave","Pascal","Erik","Sid" };
 
List<String> found;
found = stream(names).collect(partitioningBy( c -> c.startsWith("S")))
                     .get(true);

Java6

String[] names = { "Sam", "Samuel", "Dave", "Pascal", "Erik", "Sid" };
List<String> found = newList(takeWhile(names, startsWith("S")));

Challenge 7: Skipping an Arbitrary Number of Items


LINQ

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

Java Streams

String[] vipNames = { "Sam", "Samuel", "Samu", "Remo", "Arnold","Terry" };
 
List<String> skippedList;
skippedList = stream(vipNames).substream(3).collect(toList());

Java6

String[] vipNames = { "Sam", "Samuel", "Samu", "Remo", "Arnold", "Terry" };
List<String> skippedList = newList(drop(vipNames, 3));

Challenge 8: Skipping Items Based on Predicate


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.

Java6

int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 20 };
List<Integer> skippedList = newList(dropWhile(newArray(numbers), lessThan(10)));

Challenge 9: Ordering/Sorting Elements


LINQ

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

Java Streams

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

Java6

String[] friends = { "Sam", "Pamela", "Dave", "Anders", "Erik" };
friends = newArray(sort(friends), String.class);

Challenge 10: Ordering/Sorting Elements by Specific Criterium


LINQ

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

Java Streams

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

Java6

String[] friends = { "Sam", "Pamela", "Dave", "Anders", "Erik" };
friends = newArray(sort(friends, by(String_.length)), String.class);

Challenge 11: Ordering/Sorting Elements by Multiple 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

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);

Java6

String[] fruits = { "grape", "passionfruit", "banana", "apple",
                    "orange", "raspberry", "mango", "blueberry" };
fruits = newArray(sort(fruits, by(String_.length).then(
                               byNatural())), String.class);

Challenge 12: Grouping by a Criterium


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));

Java6

String[] names = { "Sam", "Samuel", "Samu", "Ravi", "Ratna", "Barsha" };
Map<Integer, List<String>> groups = groupBy(names, String_.length);

Challenge 13: Filter Distinct Elements


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();

Java6

String[] songIds = { "Song#1", "Song#2", "Song#2", "Song#2", "Song#3", "Song#1" };
newSet(songIds);

Challenge 14: Union of Two Sets


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

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();

Java6

List<String> friends1 = newList("Anders", "David", "James", "Jeff", "Joe", "Erik");
List<String> friends2 = newList("Erik", "David", "Derik");
Set<String> allMyFriends = union(newSet(friends1), newSet(friends2));

Challenge 15: First Element


LINQ

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

Java Streams

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
}

Java6

String[] otherFriends = { "Sam", "Danny", "Jeff", "Erik", "Anders", "Derik" };
Option<String> found = headOption(otherFriends);
Option<String> maybe = find(otherFriends, String_.length.andThen(equalTo(5)));
for (String m: maybe) {
    // ...
}

Challenge 16: Generate a Range of Numbers


LINQ

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

Java Streams

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

Java6

Iterable<Integer> multiplesOfEleven = filter(range(1, 100), mod(11).andThen(equalTo(0)));

Challenge 17: All


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);

Java6

String[] persons = { "Sam", "Danny", "Jeff", "Erik", "Anders", "Derik" };
boolean x = forAll(persons, String_.length.andThen(equalTo(5)));

Challenge 18: Any


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);

Java6

String[] persons = { "Sam", "Danny", "Jeff", "Erik", "Anders", "Derik" };
boolean x = exists(persons, String_.length.andThen(equalTo(5)));

Challenge 19: Zip


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); });

Java6

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

foreach(map(zip(salutations, firstNames, repeat(lastName)), mkString(" ")),
        PrintStream_.println8.apply(System.out));

Conclusion

Based on these examples I have a funny feeling that Java8 Streams API is going to be a failure. And since developers will not be able to extend it with useful constructs, it may well end up being just another nail in the coffin.

Of these examples, personally, I find the Java6 code to be the most readable. Even with its oddities, of which most are caused by the original authors decision to use ints (instead of Integers) and Lists (instead of Iterables). The ability to do this has been around since 2007, and Java8 will be released in... 2014?

I'm a bit biased, though, so what do you think?

57 comments:

  1. This:
    bool x = persons.Any(c => c.Length == 5);
    or:
    boolean x = stream(persons).anyMatch(c -> c.length() == 5);
    don't seem to be less readable than:
    boolean x = exists(persons, String_.length.andThen(equalTo(5)));

    ReplyDelete
    Replies
    1. Agreed, my statement is a bit too brave.

      In my opinion the difference in readability is so small (and many times Java6 even wins) that I don't see much point in using the Streams API. With 6 years and lambdas I'd expect something better.

      Delete
  2. Firstly there are errors in these examples, some methods are not supported in the final version of Java 8, like .boxed(), zip(). And there are also new methods which are not used as skip(n).

    Secondly, frankly, I am shocked by your conclusion, you just take things in appearance.
    Why do you say that "Based on these examples I have a funny feeling that Java8 Streams API is going to be a failure....."
    You don't know that with Java8 there are more things that you don't know with stream that we can never do them with Java6.
    Firstly when you do with something like this with stream :
    stream.filter(c -> c.contains("am"))
    .collect(toList());
    Stream dose not evaluate instruction after instruction, unlike Java6 with that API. Stream uses the power of functional programming and it makes lazy evaluation. So with Java6 code, statics methods have to copy all the involved elements for passing them to the next step and every method have to finish his actions before passing objects to an othe method, it is the same this with Linq when you use these method's .
    Through stream is evaluating all queries like one query and apply changes to the final result.
    Secondly, stream uses a very powerful iterator, when you work with collections and not the traditional iterator, it uses the Spliterator.

    Spliterator is an object for traversing and partitioning elements of a source. The source of elements covered by a Spliterator could be, for example, an array, a Collection, an IO channel, or a generator function.
    A Spliterator may also partition off some of its elements (using trySplit()) as another Spliterator, to be used in possibly-parallel operations. Operations using a Spliterator that cannot split, or does so in a highly imbalanced or inefficient manner, are unlikely to benefit from parallelism. Traversal and splitting exhaust elements; each Spliterator is useful for only a single bulk computation.

    A Spliterator also reports a set of characteristics() of its structure, source, and elements from among ORDERED, DISTINCT, SORTED, SIZED, NONNULL, IMMUTABLE, CONCURRENT, and SUBSIZED. These may be employed by Spliterator clients to control, specialize or simplify computation. For example, a Spliterator for a Collection would report SIZED, a Spliterator for a Set would report DISTINCT, and a Spliterator for a SortedSet would also report SORTED. Characteristics are reported as a simple unioned bit set. Some characteristics additionally constrain method behavior; for example if ORDERED, traversal methods must conform to their documented ordering. New characteristics may be defined in the future, so implementors should not assign meanings to unlisted values.

    With stream I can do stream().prallele().filter....or just call parallelScrem() method included in standard API and take advantage of parallelism without any effort,which allows enjoy the multi-core.

    Can you make it with Java6.

    ReplyDelete
    Replies
    1. Thank you for an insightful comment!

      This post is one year old and surely the Streams API has had time to develop further. I wouldn't call them errors, but yes, it would be fair to write a follow-up with an up-to-date comparison.

      "Stream does not evaluate instruction after instruction, unlike Java6 with that API..."
      My functional-utils library is also completely lazy. It uses Iterables, which are by definition lazy. Nothing happens until someone is actually consuming the Iterable, for example when putting the elements into a Collection. Working with infinite ranges is also totally possible.

      I'm not sure what you mean by "power of functional programming", but I've been using functional programming with Java6 at least for the past two years. Many have been doing it for even longer. You should probably try it too, if you haven't already, but you don't need Java8 to do it.

      I'm not familiar with Spliterator, but I don't see why I couldn't implement similar parallel processing if I wanted to. Why do you think the Streams API would be an inherent requirement for something like that?

      About characteristics(), I'm actually using the same pattern. If an Iterable is an instance of PossiblySizeAwareIterable, then the size information (if available) is used for example to reserve a collection of the correct size when populating the elements of the Iterable into a collection (via Collections.newList).

      "take advantage of parallelism without any effort,which allows enjoy the multi-core."
      This is somewhat a naive statement. Most of the time Java collections are so small that parallelizing them only hurts performance. As Oracle documentation states: "While aggregate operations enable you to more easily implement parallelism, it is still your responsibility to determine if your application is suitable for parallelism."

      "Can you make it with Java6."
      Yes you can. And that's the whole point. We could have been using an almost-like-java8 Java since 2007. Actually even longer but the meta-processing facilities were not standardized until then. Now, we should just use a better language and not stick with Java8.

      Delete
    2. * Java8 streams can be extended, you can even build something that resembles Linq-to-SQL. This is the main argument for Java8.
      * Java8 Lambdas are a natural fit to Java8 Streams. They go very well together.
      * Your library litters the namespace with lots of functions.
      * Your examples are quite simple, but things seem to get very messy for non-trivial tasks. Sometimes you have call a function, sometimes you have to chain function calls. In Java8 you mostly just chain functions together.
      * Java8 has also been optimized for deep inlining and for heavier usage of lambdas.
      * Java8's API doesn't rely on an external library that may or may not be maintaned
      * The size of most Java collections is not a proper counter-argument. The fact is: if you need paralellism, Java8 streams is there to help you.
      * Java8 streams are not a pre-requisite for parallel processing, but it's built in a way that lets you handle parallel processing nicely.

      Your library seems to be great, and yeah, I'd love to not use Java at all, but I am still going to have to use Java for many years to come, and I'd rather have proper features in the language itself, because it paves the ground for better libraries and better usage of the language itself.

      Delete
    3. * Java8 streams can be extended, you can even build something that resembles Linq-to-SQL. This is the main argument for Java8.
      - maybe it can be extended, I should look into it. Could you give me a hint on how to:
      1) add an operation, e.g. _tail_, _last_ or _takeWhile_ which seem to be missing?
      2) enable streams api for an existing type, e.g. Java's Optional viewed as a collection?

      * Java8 Lambdas are a natural fit to Java8 Streams. They go very well together.
      - yes, lambdas are a natural fit to pretty much anything.

      * Your library litters the namespace with lots of functions.
      - what do you mean by littering here? If you mean Functional has too many operations, maybe that's true, but most of them are already familiar to anyone used to functional programming.
      - if you mean the two different parameter-orderings for most methods, yes, that's silly, but the reason is that I do not know yet which variant to remove :)
      - if you mean the "inheritance hierarchy", I agree, it's a bloat, but it's purpose is to "overload" the same operations to work on arrays, CharSequences and Strings in addition to Iterables, so in practice it doesn't bring any more complexity. Surely, I could document this better...

      * Your examples are quite simple, but things seem to get very messy for non-trivial tasks. Sometimes you have call a function, sometimes you have to chain function calls. In Java8 you mostly just chain functions together.
      - yes, that's unfortunate. In Scala we get extendability while preserving the dot-notation, but it has its own problems regarding complexity.
      - things get complex also in Java8. Having a complex API (streams) with loads of documentation doesn't exactly help.

      * Java8 has also been optimized for deep inlining and for heavier usage of lambdas.
      - of course the JVM and javac8 are optimized. But functional libraries like mine will probably also benefit from those optimizations. A library can also be used with lambdas (as long as functional interfaces have been used), so their benefits are available way beyond the streams api. I have tried to use functional interfaces, so you can use lambdas. Please let me know if you find a weak spot.

      * Java8's API doesn't rely on an external library that may or may not be maintaned
      - being a part of a standard library is actually a _bad_ thing. Being separate would allow independent development and even replacement with better alternatives. A standard library has to be perfect because it has to remain compatible and cannot be replaced. They rarely are perfect.

      * The size of most Java collections is not a proper counter-argument. The fact is: if you need paralellism, Java8 streams is there to help you.
      - I was critisizing the "with no effort" part. There's always effort involved in evaluating whether parallelism is useful. In most cases it will only hurt performance.

      * Java8 streams are not a pre-requisite for parallel processing, but it's built in a way that lets you handle parallel processing nicely.
      - true. I haven't tried implementing parallel processing and thus I'm not aware of all the gotchas, but maybe I will try adding it to the library.

      "Your library seems to be great..."
      - thanks, though I'm not sure if it's _great_. It's an effort to bring functional programming with first-class-functions to Java, before java8 was around. I like it myself and we use it in production, so at least it's not a total disaster ;). I'm not aware of realistic alternatives: Guava is not good, LambdaJ has issues, FunctionalJava seems to only have the "math side" of things. Java8 might be (or become) an alternative, but I do not know yet. It certainly has less features than my library (e.g. you cannot use fields as first-class-functions).

      Thanks for great comments!

      Delete
  3. I wrote a follow-up with updated examples: http://blog.lahteenmaki.net/2014/05/java-streams-vs-c-linq-vs-java6-updated.html

    ReplyDelete
  4. The distinguish between java stream vs c linq vs java 6 are really helpful.These codings and 20 challenges are really helpful to more understand.Thank you.

    Cloud Computing Training in Chennai | Selenium Training in Chennai

    ReplyDelete
  5. Really awesome blog. Your blog is really useful for me. Thanks for sharing this informative blog. Keep update your blog.
    QTP Training in Chennai

    ReplyDelete
  6. Whatever we gathered information from the blogs, we should implement that in practically then only we can understand that exact thing clearly, but it’s no need to do it, because you have explained the concepts very well. It was crystal clear, keep sharing..
    Microsoft SQL Server Training In Chennai

    ReplyDelete
  7. Excellent post!!! Selenium automation testing tool makes your software validation process lot simpler. Keep on updating your blog with such awesome information. Selenium Training in Chennai | Selenium Course in Chennai | Best Selenium training institute in Chennai

    ReplyDelete
  8. GSSSB 2480 Revenue Talati Bharti Recruitment 2016

    Very rare and helpful Information to every one .................. Keep writing this kind of articles..............

    ReplyDelete
  9. Latest technology have created a greater impact over testing web applications. This vital in identifying important issues that raises in web appplications. Thanks for sharing this information in here. Keep blogging article like this.

    Selenium training in chennai | Selenium testing training | Selenium testing tool training chennai

    ReplyDelete
  10. The content published here was worth able to read and share. The aspect in which you have written the content is amazing. I have bookmarked this page for future use. Thanks for sharing this in here. Keep blogging content like this.

    Software testing training in chennai | Software testing training | Software testing course chennai

    ReplyDelete
  11. This comment has been removed by the author.

    ReplyDelete
  12. Really awesome blog. Your blog is really useful for me.
    Thanks for sharing this informative blog. Keep update your blog.
    Oracle Training In Chennai

    ReplyDelete
  13. This Java stream vs C# and the java 6 explanation is excellent.It is fully explained in coding concept and it is a wonderful thing.
    SAP BASIS Training in Chennai

    ReplyDelete
  14. A very nice guide. I will definitely follow these tips. Thank you for sharing such detailed article. I am learning a lot from you.


    Peridot Systems Chennai Reviews

    ReplyDelete
  15. Helpful as always. Every post you write produce a massive value to your readers that is the only reason it is so popular and has great authority.

    SAP training in Chennai

    ReplyDelete
  16. Thanks for the good words! Really appreciated. Great post. I’ve been commenting a lot on a few blogs recently, but I hadn’t thought about my approach until you brought it up.

    SEO training in Adyar

    ReplyDelete
  17. People usually say about ios-applications-development.
    ..you're right...we have much difference between these term. Thanks for informative share!IOS 7 app designs

    ReplyDelete
  18. Good job! Congrats

    ReplyDelete
  19. Thanku for shariong..
    Informatica training, in the recent times has acquired a wide scope of popularity amongst the youngsters at the forefront of their career.
    Informatica online training in hyderabad



    ReplyDelete
  20. The usage of third party storage system for the data storage can be avoided in cloud computing and we can store, access the data through internet.
    cloud computing training in chennai | cloud computing courses in chennai

    ReplyDelete
  21. Awesome..You have clearly explained …Its very useful for me to know about new things..Keep on blogging..
    seo institute in chennai

    ReplyDelete
  22. Well Said, you have furnished the right information that will be useful to anyone at all time. Thanks for sharing your Ideas.
    Python Training in Chennai | Python Course in Chennai

    ReplyDelete
  23. Good post. Happy to visit your blog. Thanks for sharing.

    Social Media Marketing Training in Chennai

    ReplyDelete

  24. Hadoop online training in hyderabad.All the basic and get the full knowledge of

    hadoop.
    hadoop online training in

    hyderbad


    ReplyDelete
  25. Great article. Happy to visit your blog. Thanks for sharing such a useful post.

    digital marketing training

    ReplyDelete
  26. Other than the first few comments, the rest sound suspiciously contrived. Anyways, I grew up learning Java and spent much of my schooling learning Java, and now program in C# professionally, and if you're saying that the Java 6 examples are the most clear then I'm completely baffled. The very nature of the examples is not intuitive. Yes they use functional construction, but the construction is backwards from how you would normally read a statement. Starting from the inside and working out works in mathematics, but it's not how humans naturally read things. The Linq examples are far clearer IMO, and based on the prevalence of many modern languages borrowing functional concepts (Scala, Rust, F#, Python, Ruby) it seems that this approach is preferred.

    I know it's your opinion, but I'm surprised that none of the comments have pointed this out.

    ReplyDelete
  27. Other than the first few comments, the rest sound suspiciously contrived. Anyways, I grew up learning Java and spent much of my schooling learning Java, and now program in C# professionally, and if you're saying that the Java 6 examples are the most clear then I'm completely baffled. The very nature of the examples is not intuitive. Yes they use functional construction, but the construction is backwards from how you would normally read a statement. Starting from the inside and working out works in mathematics, but it's not how humans naturally read things. The Linq examples are far clearer IMO, and based on the prevalence of many modern languages borrowing functional concepts (Scala, Rust, F#, Python, Ruby) it seems that this approach is preferred.

    I know it's your opinion, but I'm surprised that none of the comments have pointed this out.

    ReplyDelete
  28. Great article. Happy to visit your blog. Thanks for sharing such a useful post.
    unix Training in Chennai



    ReplyDelete
  29. Thanku for shariong..
    java training, in the recent times has acquired a wide scope of popularity amongst the youngsters at the forefront of their career.
    java Training in Chennai




    ReplyDelete
  30. Take a look AbacusUtil at: http://www.landawn.com

    ReplyDelete
  31. Excellent post!!!. The strategy you have posted on this technology helped me to get into the next level and had lot of information in it.
    salesforce training in chennai | salesforce training institute in chennai

    ReplyDelete
  32. Great article. Thanks for sharing such a useful post.

    wordpress Training center in Chennai

    ReplyDelete
  33. Great article. Thanks for sharing such a useful post.
    perl training in chennai

    ReplyDelete
  34. Well Said, you have furnished the right information that will be useful to anyone at all time. Thanks for sharing your Ideas.
    oracle training in chennai | oracle training institutes in chennai

    ReplyDelete
  35. Quite a useful post, I learned some new points here. Thanks admin please keep posting updates regularly to enlighten our knowledge.
    PHP Training in Chennai | PHP Course in Chennai

    ReplyDelete
  36. very helpful for my site. I always follow your tips....
    informatica training in chennai

    ReplyDelete
  37. Great content thanks for sharing this informative blog which provided me technical information keep posting.
    Selenium Training in Chennai | Selenium Testing Course in Chennai

    ReplyDelete
  38. Well Said, you have furnished the right information that will be useful to anyone at all time. Thanks for sharing your Ideas.
    Salesforce Training in Chennai | Salesforce Training Institute in Chennai

    ReplyDelete
  39. This comment has been removed by the author.

    ReplyDelete
  40. Awesome blog post.


    Click here to go to the best digital marketing training in Chennai

    ReplyDelete
  41. Great post!! This can be one particular of the most useful blogs We’ve ever arrive across on this subject. Basically Wonderful. I am also a specialist in this topic so I can understand your hard work.
    Selenium Training in Chennai

    ReplyDelete
  42. Great post!! This can be one particular of the most useful blogs We’ve ever arrive across on this subject. Basically Wonderful. I am also a specialist in this topic so I can understand your hard work

    Best Digital Marketing Training in Chennai | Best Digital Marketing Course in Chennai

    ReplyDelete
  43. wow!! Great post, Thanks a lot for your efforts. Really inspiring and you have very good programming knowledge.
    Selenium training in Chennai | Best Selenium training institute in Chennai

    ReplyDelete