Sunday, 28 September 2014

Java 8 - using collect in the Stream API

The following code povides some examples how to do collect() in the Java Stream API.



import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.cert.PKIXRevocationChecker.Option;
import java.time.LocalDate;
import java.time.Month;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 *
 * @author José
 */
public class DataAndTime {

    public static void main(String[] args) {

        List<Person> persons = new ArrayList<>();
        
        try (
            BufferedReader reader = 
                new BufferedReader(
                    new InputStreamReader(
                        DataAndTime.class.getResourceAsStream("people.txt")));
            Stream<String> stream = reader.lines();
        ) {
            
            stream.map(
               line -> {
                   String[] s = line.split(" ");
                   String name = s[0].trim();
                   int year = Integer.parseInt(s[1]);
                   Month month = Month.of(Integer.parseInt(s[2]));
                   int day = Integer.parseInt(s[3]);
                   Person p = new Person(name, LocalDate.of(year, month, day));
                   persons.add(p);
                   return p;
               })
               .forEach(System.out::println);
            
            Optional<Person>opt = persons.stream().filter(p -> p.getAge() >= 20)
            .min(Comparator.comparing(Person::getAge));
            
            System.out.println("Youngest person among all persons: " + opt); 
            
            Optional<Person>optSecond = persons
              .stream()
              .max(Comparator.comparing(Person::getAge)); 
            
            System.out.println("Oldest person among all persons: " + optSecond);    
            
            Map<Integer, Long> map = 
              persons.stream()
              .collect(Collectors.groupingBy(
                Person::getAge, Collectors.counting())); 
            
            System.out.println(map);
            
            Map<Integer, List<String>> mapSecond = 
              persons.stream()
              .collect(Collectors.groupingBy(
                Person::getAge, 
                Collectors.mapping(
                  Person::getName,
                  Collectors.toList()
                  )
                )); 
            
            System.out.println(mapSecond);
            
            Map<Integer, Set<String>> mapThird = 
              persons.stream()
              .collect(Collectors.groupingBy(
                Person::getAge, 
                Collectors.mapping(
                  Person::getName,
                  Collectors.toCollection(TreeSet::new)
                  )
                )); 
            
            System.out.println(mapThird);
            
            Map<Integer, String> mapFourth = 
              persons.stream()
              .collect(Collectors.groupingBy(
                Person::getAge, 
                Collectors.mapping(
                  Person::getName,
                  Collectors.joining(", ")
                  )
                )); 
            
            System.out.println(mapFourth);
            
            
            
        } catch (IOException ioe) {
            System.out.println(ioe);
        }

        LocalDate now = LocalDate.of(2014, Month.MARCH, 12);
        
        persons.stream().forEach(
                p -> {
                    Period period = Period.between(p.getDateOfBirth(), now);
                    System.out.println(p.getName() + " was born " +
                            period.get(ChronoUnit.YEARS) + " years and " + 
                            period.get(ChronoUnit.MONTHS) + " months " + 
                            "[" + p.getDateOfBirth().until(now, ChronoUnit.MONTHS) 
                            + " months]"
                            );
                    
                });
    }
}

The definition of Person class:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */


import java.time.LocalDate;
import java.time.chrono.IsoChronology;

/**
 *
 * @author José
 */
public class Person {
    
    private String name;
    private LocalDate dateOfBirth;
    
    public Person(){}
    
    public Person(String name, LocalDate dateOfBirth) {
        this.name = name;
        this.dateOfBirth = dateOfBirth;
    }

    public String getName() {
        return name;
    }

    public LocalDate getDateOfBirth() {
        return dateOfBirth;
    }
    

 public int getAge(){
  return dateOfBirth.until(IsoChronology.INSTANCE.dateNow()).getYears();  
 }

    @Override
    public String toString() {
        return "Person{" + "name=" + name + ", dateOfBirth=" + dateOfBirth + '}';
    }
}


The sample persons are collected from this text file:

Sarah 1999 12 15
Philip 1993 8 12
Beth 1991 6 5
Simon 1990 3 23
Nina 1991 7 12
Allan 1985 2 14
Leonard 1996 10 27
Barbara 1988 4 19

Here is a sample Stream API query to retrieve a comma separated string of the names of the persons in the list, as an additional example of how to retrieve information from an entire collection without using collect, but with map and reduce:

   Optional personNames = persons.stream().map(p->p.getName()).reduce((p1,p2)-> p1 + "," + p2);
            System.out.println(personNames);       

Using immutability in Java to support functional programming and avoid side effects

The following article is based on Venkat Subramaniam's article "Programming with immutability in Java" in "The Developer" magazine No. 3 2013. The code presented below shows how Java 8 supports immutability with different techniques. Consider the following Java 8 code sample:

import java.util.*;
import java.util.stream.*;

public class ImmutableTest1 {

 public static void printTotal(Stream<Integer> values){
  long start = System.nanoTime(); 
  final int total = 
   values
   .filter(value->value>3)
   .filter(value->isEven(value))
   .mapToInt(value->value*2)
   .sum(); 

   long end = System.nanoTime(); 
   System.out.printf("Total: %d Time: %.3f seconds\n", total, (end - start)/1.0e9); 

 }

 public static boolean isEven(int number){
  try {
   Thread.sleep(100); 
  }
  catch (Exception ex){   
   System.out.println(ex.getMessage());
  }
  return number % 2 == 0; 
 }

 public static void main(String[] args){
  List<Integer>values = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
  printTotal(values.stream());
  printTotal(values.parallelStream());
  
  for (int element : values) {
   Runnable runnable = () -> System.out.println(element);
   runnable.run();
  }
  
  List<String> namesList = Arrays.asList("Jake", "Raju", "Kim", "Kara", "Paul", "Brad", "Mike"); 
  System.out.println("Found a 3 letter name?: " + 
    namesList.stream().anyMatch(name->name.length() == 3)); 
  
  System.out.println("Found Kim?: " + 
    namesList.stream().anyMatch(name-> name.contains("Kim")));
 }

}

The code above shows how library functions in the Stream API of Java 8 avoids the use of mutable variables by the functional programming code style of chaining. Further, note that the use of a classical for loop prohibits the loop creating new Runnable instances, while the for loop over a collection allows this. The error given for classical for loop is: Local variable i defined in an enclosing scope must be final or effectively final ImmutableTest1.java /ImmutabilityTest1/src line 36 Java Problem given this code:
 for (int i = 0; i < values.size(); i++) {
   Runnable runnable = () -> System.out.println(values.get(i));
   runnable.run();
        }
In addition, recursion is a technique that provides immutability to your code, by avoiding use of mutable control variables, example follows:

import java.util.Scanner;


public class Guesser {
 
 final static int target = (int) (Math.random() * 100); 
 
 public static void play(final int attempts){
  System.out.print("Enter your guess:");
  final int guess = new Scanner(System.in).nextInt();
  if (guess < target)
   System.out.println("Aim higher"); 
  if (guess > target)
   System.out.println("Aim lower");
  
  if (guess == target)
   System.out.printf("You got it in %d attempts\n", attempts);
  else 
   play(attempts+1);
  
 }
 
 public static void main(String[] args){
  System.out.println("I've selected a number, can you guess?"); 
  play(1);
 }

}


Thursday, 25 September 2014

Speeding up Java code execution using parallel execution

Disclaimer note: I am a C# programmer and only have some work experience with Java. The new features of Java 8 makes me as a code much more enthustiastic to this language, since parallel programming, functional programming and collection handling now is much better! In Java, using the Stream Api makes parallel computing easily accessible. Consider this simple code:

import java.io.*; 
import java.util.*; 
import java.util.stream.Stream;

public class FileTest {

 public static void processFile(File file){
  try {
         Thread.sleep(100 + (int)(Math.random()*2000));
         System.out.println(file.getAbsolutePath());
  }
  catch (Exception ex){
   System.out.println(file); 
  }
 }
 
 public static void main(String[] args){
  
  File currentDir = new File("."); 
  File[] children = currentDir.listFiles(); 

  Stream.of(children).forEach(
   file -> processFile(file)); 

 }
}

To speed up the execution of this simple code, just add parallel() before the .forEach:

import java.io.*; 
import java.util.*; 
import java.util.stream.Stream;

public class FileTest {

 public static void processFile(File file){
  try {
         Thread.sleep(100 + (int)(Math.random()*2000));
         System.out.println(file.getAbsolutePath());
  }
  catch (Exception ex){
   System.out.println(file); 
  }
 }
 
 public static void main(String[] args){
  
  File currentDir = new File("."); 
  File[] children = currentDir.listFiles(); 

  Stream.of(children).parallel().forEach(
   file -> processFile(file)); 

 }
}

All these features makes Java 8 a much more attractive language again, and definately more C# developers will look more into Java soon! :-) Some images from Sublime Text 3, which I use to compile and run the code above!

Wednesday, 24 September 2014

Introductory Java 8 Lambda and collection handling

As a disclaimer, I have coded C# for several years now and am familiar with .NET technology, but my experience with Java 8 is more limited, so this article is just introductory level Java 8 Lambda and collection handling. I will mainly present code examples for handling collections and using lambda expressions in Java 8, using the Eclipse Luna IDE. I also downloaded Jdk 8 to get the necessary Java Development Kit and Java 8 runtime required. The code presented here is heavily based on the tutorial Oracle provides on their websites: Lambda Expressions in Java Let's look at some code right away, defining some classes and enums:

import java.time.LocalDate;
import java.time.chrono.IsoChronology;
import java.util.ArrayList;
import java.util.List;

public class Person {

 String name;  
 Sex gender; 
 LocalDate birthday; 
 String emailAddress; 

 Person(String nameArg, LocalDate birthdayArg, Sex genderArg, String emailArg){
  name = nameArg;
  birthday = birthdayArg; 
  gender = genderArg; 
  emailAddress = emailArg;   
 }
 
 public int getAge(){
  return birthday.until(IsoChronology.INSTANCE.dateNow()).getYears();  
 }
 
 public void printPerson(){
  System.out.println(name + ", " + this.getAge());   
 }
 
 public Sex getGender(){
  return gender;
 }
 
 public String getName(){
  return name;
 }
 
 public String getEmailAddress(){
  return emailAddress;
 }
 
 public LocalDate getBirthday(){
  return birthday;
 }
 
 public static int compareByAge(Person a, Person b){
  return a.birthday.compareTo(b.birthday); 
 }
 
 public static List createRoster(){
  List roster = new ArrayList(); 
  roster.add(new Person(
    "Fred", 
    IsoChronology.INSTANCE.date(1991, 6, 20),
    Sex.MALE,
    "fred@example.com")); 
  roster.add(new Person(
    "Jane", 
    IsoChronology.INSTANCE.date(1990, 7, 15),
    Sex.FEMALE,
    "jane@example.com")); 
  roster.add(new Person(
    "George", 
    IsoChronology.INSTANCE.date(1993, 8, 13),
    Sex.MALE,
    "george@example.com")); 
  roster.add(new Person(
    "Bob", 
    IsoChronology.INSTANCE.date(2000, 9, 12),
    Sex.MALE,
    "bob@example.com"));   
  return roster;
 }
 

}



public class SimplePerson {

 public SimplePerson(String nameArg, int ageArg) {
  name = nameArg;
  age = ageArg;
 }
 
 String name;
 int age;
 
 public String getName(){
  return name;
 }
 
 public int getAge(){
  return age;
 }
 
}


public enum Sex {
 
 MALE,
 
 FEMALE

}



public interface ICheckPerson {
 
 boolean test(Person p);

}




The following code makes use of these definitions and demonstrates use of lambda and collections in Java 8:

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Collectors;


public class RosterTest {
 
 //Approach 1: Create methods that Search for Persons that match one characteristics
 
 public static void printPersonsOlderThan(List<Person> roster, int age){
  for (Person p : roster){
   if (p.getAge() >= age){
    p.printPerson();
   }
  }  
 }

 
 //Approach 2: Create more generalized search methods 
 
 public static void printPersonsWithinAgeRange(
   List<Person> roster, int low, int high){
  for (Person p : roster){
   if (low <= p.getAge() && p.getAge() < high){
    p.printPerson();
   }
  }
 }
 
 
 //Approach 3: Specify search criteria code in a local class
 //Approach 4: Specify Search criteria code in an anonymous class
 //Approach 5: Specify search criteria code with a lambda expression
 public static void printPersons(
   List<Person> roster, ICheckPerson tester){
  for (Person p : roster){
   if (tester.test(p)){
    p.printPerson();       
   }
  }
 }
 
 
 //Approach 6: Use standard functional interfaces with lambda expressions
 public static void processPersonsWithPredicate(
   List<Person> roster,
   Predicate<Person> tester){
  for (Person p : roster){
   if (tester.test(p)){
    p.printPerson();
   }
  }  
 }
 
 
 //Approach 7, second example
 
 public static void processPersonsWithFunction(
   List<Person> roster,
   Predicate<Person> tester,
   Function<Person, String> mapper,
   Consumer<String> block){
  for (Person p : roster){
   if (tester.test(p)){
    String data = mapper.apply(p);
    block.accept(data); 
   }
  }
 }
 
 
 //Approach 8: Use generics more extensively
 
 public static <X,Y> void processElements(
   Iterable<X> source,
   Predicate<X> tester,
   Function<X,Y> mapper,
   Consumer<Y> block) {
  for (X p : source){
   if (tester.test(p)){
    Y data = mapper.apply(p);
    block.accept(data);
   }   
  }
 }
 
 
 
 public static void main(String... args){
  
  List<Person> roster = Person.createRoster(); 
  
  for (Person p : roster){
   p.printPerson();
  }
  
  //Approach 1: Create methods that Search for Persons that match one characteristic
  
  System.out.println("Persons older than 20:"); 
     printPersonsOlderThan(roster, 20);
     System.out.println();
     
     //Approach 2 : Create more generalized search methods 
     
     System.out.println("Persons between the ages of 14 and 30:"); 
     printPersonsWithinAgeRange(roster, 14, 30);
     System.out.println();
     
     //Approach 3 : Specify search criteria code in local class 
     
     System.out.println("Persons who are eligible for Selective Service:"); 
     
     class CheckPersonEligibleForSelectiveService implements ICheckPerson{

   @Override
   public boolean test(Person p) {
    return p.getGender() == Sex.MALE
      && p.getAge() >= 18 
      && p.getAge() <= 25;
   }      
     }
     
     printPersons(roster, new CheckPersonEligibleForSelectiveService());
     
     System.out.println();
     
     //Approach 4: Specify search Criteria code in an Anonymous class 
     
     System.out.println("Persons who are eligible for Selective Service " + 
      "(anonymous class)");
     
     printPersons(roster, new ICheckPerson() {   
   public boolean test(Person p) {
    return p.getGender() == Sex.MALE
      && p.getAge() >= 18
      && p.getAge() <= 25;
   }
     }); 
  
     //Approach 6: Use standard functional interfaces with lambda expressions 
     
     System.out.println("Persons who are eligible for Selective Service " + 
     "(with Predicate parameter):"); 
     
     processPersonsWithPredicate(roster,
       p -> p.getGender() == Sex.MALE
         && p.getAge() >= 18
         && p.getAge() <= 25
         );
     
     //Approach 7, second example 
     
     System.out.println();
     
     processPersonsWithFunction(roster, p -> 
     p.getGender() == Sex.MALE
     && p.getAge() >= 18 
     && p.getAge() <= 25, 
     p -> p.getEmailAddress(), 
     email -> System.out.println(email));
     
     System.out.println();
     
     //Approach 8: Use generics more extensively 
     
     System.out.println("Persons who are eligible for Selective Service " + 
     "(generic version):"); 
     processElements(roster, p -> 
     p.getGender() == Sex.MALE
     && p.getAge() >= 18 
     && p.getAge() <= 25, 
     p -> p.getEmailAddress(), 
     email -> System.out.println(email));
     
     //Approach 9: Bulk data operations that accept lambda expressions as parameters 
     
     System.out.println("Persons who are eligible for Selective Service " + 
      "(with bulk data operations):"); 
     
     roster.stream().filter(
       p -> p.getGender() == Sex.MALE
       && p.getAge() >= 18
       && p.getAge() <= 25)
       .map(p -> p.getEmailAddress())
       .forEach(email -> System.out.println(email));
     
     
     //Approach 10: Creating a new collection from a query 
     
     System.out.println("Persons who are eligible for selective Service " + 
     "(with collect to create new collection"); 
     
     List<Person> selectiveServicePersons = roster.stream().filter(
       p -> p.getGender() == Sex.MALE
       && p.getAge() >= 18 
       && p.getAge() <= 25)
       .collect(Collectors.<Person>toList()); 
     
     for(Person p: selectiveServicePersons){
      p.printPerson();
     }     
        
     
     System.out.println();
     
     //Approach 11: Using map to transform a collection to another type of collection    
     
     List<SimplePerson> personsTransformed = (List<SimplePerson>) roster.stream()
       .map(p->new SimplePerson(p.getName(), p.getAge()))
    .collect(Collectors.<SimplePerson>toList()); 
     
     for(SimplePerson p: personsTransformed){
      System.out.println(p.getName() + ", " + p.getAge()); 
     }
     
     System.out.println();
     
     //Approach 12: Using sorting for Approach 11 
     
     List<SimplePerson> personsTransformedSorted = (List<SimplePerson>) roster.stream()       
       .map(p->new SimplePerson(p.getName(), p.getAge()))
    .collect(Collectors.<SimplePerson>toList()); 
     
     class CustomComparator implements Comparator<SimplePerson>{
      @Override
      public int compare(SimplePerson o1, SimplePerson o2) {
       return o1.getAge() - o2.getAge();
      };
     }
     
     Collections.sort(personsTransformedSorted, new CustomComparator());
     
     for(SimplePerson p: personsTransformedSorted){
      System.out.println(p.getName() + ", " + p.getAge()); 
     }
     
     System.out.println();
     
     //Approach 13: Grouping sorting by gender 
     
     Map<Sex, List<Person>> mapByGenderMap = 
       roster.stream().collect(Collectors.groupingBy(Person::getGender));
     
     for (Map.Entry<Sex, List<Person>> entry : mapByGenderMap.entrySet()){
     
      System.out.println("Persons that are: " + entry.getKey());
      for (Person person : entry.getValue()) {
       person.printPerson();
      }      
     }  

     System.out.println();
     
     //Approach 14: Comparator that is implemented on the fly 
     List<Person> personsSortedByNameList = roster.stream()
       .sorted(new Comparator<Person>() {
        public int compare(Person x, Person y){
         return x.getName().compareTo(y.getName());
        }
    }).collect(Collectors.toList());
     
     System.out.println("Persons sorted by name");
     for (Person person : personsSortedByNameList){
      person.printPerson();
     }  

   //Approach 15: Comparator that is implemented on the fly using a lambda expression 
   List<Person> personsSortedByNameThroughLambdaList  =  roster.stream()
     .sorted((x,y)-> x.getName()
     .compareTo(y.getName())).collect(Collectors.toList()); 
     
    System.out.println("Persons sorted by name through lambda:");
     
    for (Person person : personsSortedByNameThroughLambdaList)
    {
      person.printPerson();
    }        
          
 } 
   

}


First perspectives of the Java 8 support

From looking through the sample code, one can see that Java 8 has got support for most of what LINQ offers, there are also some major drawbacks or shortcomings that are clear. I am not experienced with Java 8, so perhaps some of my considerations here are either wrong or inprecise, but overall the syntax of Java 8 is much more verbose and less fluent than that of LINQ. Also, there are differences between Java 8 and C#. The Consumer concept of Java is great and looks like a missing part in C#. While Java 8 uses ->, C# uses =>, and the rest of the functional syntax is very similar. Runnable also looks like Action of C#. The anonymous class concept of Java is however flawed compared to C# true anonymous functions. To do projections and a requirement to create a new class definition or interface definition is not very flexible. Instantiating interfaces is supported in Java and not in C#, this is however a positive feature of Java that C# lacks. Java supports also default implementations and static implementations in interfaces, which is very practical in many cases - C# does not support these default methods inside interfaces. To do grouping and sorting requires implementing comparators and groupings go via maps. All in all, C# and LINQ is so more flexible and the chaining syntax makes complicated functional programming easy. In Java 8, much functional programming is possible - in fact most functional programming that's supported in LINQ is also supported in Java 8 I guess - it is just so verbose, fragmented and indirect to do basic things such as sorting. I also like the true anonymous functions of C# using thew new { } syntax, which Java 8 seems to lack. The dynamic type inference that the "var" keyword of C# supports seems also to lack when working with Java 8 - you often have to help the compiler by doing specific casts. Again, there might be some misunderstandings here, but all in all Java 8 functional programmings seems "harder" than using C# and LINQ, but I guess this will improve as Java 8 now has got functional programming support. Also, Scala and Clojure are similar languages that are alternatives, where functional programming have been supported for years and have matured. It looks like Java's "marriage" with Oracle has halted progression and while Java 8 has evolved, there are still many parts of the language that can be improved to support functional programming. However, much about Java 8 is positive and it is to be expected that more C# developers (and VB?) will be attracted to Java since it now supports functional programming. But beware, C# programmers - here be dragons! There will be a learning curve and that compact syntax of C# you have learned to love is not the same experience when doing Java 8 functional programming!