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

Sunday 28 September 2014

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!