Monday, 23 January 2017

Using c-namespace in Spring

If you have worked on Spring and used XML configuration for wiring beans you would have used <constructor-arg> element several times for providing, property values and/or providing reference for beans, as a constructor injection. If you are looking for any shorter alternative, just as p-namesapce is used in place of nested <property> element, you can use c-namespace.

The c-namespace enables you to use the bean element’s attributes for configuring the constructor arguments rather than nested constructor-arg elements.

As example –

If you have an XML configuration for bean employee which has a constructor that refers to the bean of type address with constructor-arg you will write it like this -

<bean id="employee" class="org.netjs.model.Employee">
    <constructor-arg ref="address"/>
</bean>

You can use c-namespace to shorten it like this -

<bean id="employee" class="org.netjs.model.Employee" c:officeAddress-ref="address">
    <!-- <constructor-arg ref="address"/> -->
</bean>

You can see here that instead of using nested <constructor-arg> element you can use bean element’s attribute itself.

In this way of using c-namespace for injection of bean reference c:officeAddress-ref="address", c: denotes the use of c-namespace, officeAddress is the constructor argument name with in the employee class where value is injected, -ref indicates injection of bean reference.

For literals

Same way c-namespace can be used for injecting literal values.

As example

If you have an XML configuration for bean employee which has a constructor argument empName then you can provide a literal value to empName property like this –

<bean id="employee" class="org.netjs.model.Employee">
    <constructor-arg value="Ram"/>
</bean>

Using c-namespace you can shorten it like this –

<bean id="employee" class="org.netjs.model.Employee" c:empName="Ram">
    <!-- <constructor-arg value="Ram"/> -->
</bean>

Full example

As we have already seen there are two classes Address and Employee and Address class bean is referred in Employee.

Employee class

public class Employee {
 private int empId;
 private String empName;
 private int age;
 private Address officeAddress;
 
 public Employee(int empId, String empName, int age, Address officeAddress){
  this.empId = empId;
  this.empName = empName;
  this.age = age;
  this.officeAddress = officeAddress;
 }
 
 public Address getOfficeAddress() {
  return officeAddress;
 }
 
 public int getEmpId() {
  return empId;
 }
 
 public String getEmpName() {
  return empName;
 }
 
 public int getAge() {
  return age;
 }
}

Here it can be seen that Employee class has constructor that has some literal values as argument and one argument of type Address.

Address Class

public class Address {
 private String number; 
 private String street; 
 private String city; 
 private String state; 
 private String pinCode; 
 public String getNumber() {
  return number;
 }
 public void setNumber(String number) {
  this.number = number;
 }
 public String getStreet() {
  return street;
 }
 public void setStreet(String street) {
  this.street = street;
 }
 public String getCity() {
  return city;
 }
 public void setCity(String city) {
  this.city = city;
 }
 public String getState() {
  return state;
 }
 public void setState(String state) {
  this.state = state;
 }
 public String getPinCode() {
  return pinCode;
 }
 
 public void setPinCode(String pinCode) {
  this.pinCode = pinCode;
 }
 
}

XML Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
   
    
    <bean id="address" class="org.netjs.model.Address" p:number="101" p:street="M I Road" 
            p:city="Jaipur" p:state="Rajasthan" p:pinCode="302001"> 
    </bean>
    
    <bean id="employee" class="org.netjs.model.Employee" c:empId="1001" c:age="25" c:empName="Ram" c:officeAddress-ref="address" />
    
</beans>
Here notice the inclusion of xmlns:c="http://www.springframework.org/schema/c” and xmlns:p="http://www.springframework.org/schema/p” in XML configuration for c-namespace and p-namespace respectively.

In bean definition for address p-namespace is used for providing values. In bean definition for Employee c-namespace is used to provide values for constructor arguments.

Test Class

You can run this code using the following code -

import org.netjs.model.Address;
import org.netjs.model.Employee;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

    public static void main(String[] args) {
        
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
        Employee emp = (Employee)context.getBean("employee");  
        Address addr = emp.getOfficeAddress();
        System.out.println("name " + emp.getEmpName());
        System.out.println("City " + addr.getCity());
        System.out.println("PinCode " + addr.getPinCode());
        context.close();    
    }

}

Output

name Ram
City Jaipur
PinCode 302001 

That's all for this topic Using c-namespace in Spring. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. What is Dependency Injection in Spring
  2. Using p-namespace for shorter XML in Spring
  3. Injecting inner bean in Spring
  4. Select query using JDBCTemplate in Spring framework
  5. Using Conditional annotation in Spring framework

You may also like -

>>>Go to Spring tutorial page

Wednesday, 18 January 2017

Spliterator in Java

Spliterators, like iterators, are for traversing the 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.

As the name suggests, spliterator can split the source and iterate the splitted parts in parallel. That way a huge data source can be divided into small sized units that can be traversed and processed parallely.

Spliterator interface

Spliterator is a generic interface in Java defined as -

Interface Spliterator<T>

Where T is the type of elements returned by this Spliterator.

Spliterator methods

Though spliterator will increase performance by traversing the collection in parallel but you can also use spliterator even if you are not using parallel execution.

If you use iterator you have to use two methods hasNext() to ensure that there is next element and then next() method to use that element. Spliterator provides methods that combines these two methods into one and making it more convenient to use.

Some of the frequently used methods of Spliterator are -

  • tryAdvance() - If a remaining element exists, performs the given action on it, returning true; else returns false. Its form is -
    tryAdvance(Consumer<? super T> action)
    
    Here action is an instance of Consumer, which is a functional interface, it specifies the function that has to be applied on the next element while traversing the collection (or any other source).
  • forEachRemaining - Performs the given action for each remaining element, sequentially in the current thread, until all elements have been processed or the action throws an exception. Its form is -
    default void forEachRemaining(Consumer<? super T> action)
    
  • estimateSize() - Returns an estimate of the number of elements that would be encountered by forEachRemaining traversal, or returns Long.MAX_VALUE if infinite, unknown, or too expensive to compute. Its form is -
    long estimateSize()
    
  • trySplit() - If current spliterator can be partitioned a new spliterator is created, it partitions the elements of the source so that new spliterator traverse one of the partition while original spliterator traverses the other partition.
  • characteristics() - Returns a set of characteristics of this Spliterator and its elements.

Spliterator characteristics

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 characteristics are defined as constant fields in the Spliterator interface.

Read more about them here - https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html#characteristics--

To see constant values - https://docs.oracle.com/javase/8/docs/api/constant-values.html#java.util.Spliterator

Using characteristics() method will give you a result represented as ORed values of the characterstics relevant for the given source.

Spliterator example code

If you have a list of names and you want to iterate it and print the names, using iterator it can be done like -

public class IteratorDemo {

    public static void main(String[] args) {
        List<String> nameList = Arrays.asList("Ram", "Sheila", "Mukesh", "Rani", "Nick", "Amy", "Desi", "Margo");
        Iterator<String> itr = nameList.iterator();
        while (itr.hasNext()) {
            System.out.println("name - " + itr.next());   
        }
    }
}

Same thing can be done using spliterator like this -

public class SpliteratorDemo {

    public static void main(String[] args) {
        List<String> nameList = Arrays.asList("Ram", "Sheila", "Mukesh", "Rani", "Nick", "Amy", "Desi", "Margo");
        Spliterator<String> splitStr = nameList.spliterator();
        while(splitStr.tryAdvance((n) -> System.out.println("name - " + n)));
    }

}

Here you can see you need to use only one method tryAdvance() which combines both hasNext() and next() methods of the iterator.

Using forEachRemaining

If you want to convert all the names to lowercase you can use forEachRemaining method.

import java.util.Arrays;
import java.util.List;
import java.util.Spliterator;

public class SpliteratorDemo {

    public static void main(String[] args) {
        List<String> nameList = Arrays.asList("Ram", "Sheila", "Mukesh", "Rani", "Nick", "Amy", "Desi", "Margo");
        Spliterator<String> splitStr = nameList.spliterator();
        splitStr.forEachRemaining( 
            (n) -> {
                String x = n.toLowerCase();
                System.out.println("" + x);
            }
        );
    }

}

Using trySplit

If you want to split the original spliterator so that you can traverse the element parallely.

import java.util.Arrays;
import java.util.List;
import java.util.Spliterator;

public class SpliteratorDemo {

    public static void main(String[] args) {
        List<String> nameList = Arrays.asList("Ram", "Sheila", "Mukesh", "Rani", "Nick", "Amy", "Desi", "Margo");
        Spliterator<String> splitStr = nameList.spliterator();
        Spliterator<String> splitStr2 = splitStr.trySplit();
        // Check if splitting actually happened, then use it
        if(splitStr2 != null){
            System.out.println("Spliterator-2");
            while(splitStr2.tryAdvance((n) -> System.out.println("name - " + n)));
        }
        // Original spliterator
        System.out.println("Original Spliterator");
        while(splitStr.tryAdvance((n) -> System.out.println("name - " + n)));
    }
        
}

Output

Spliterator-2
name - Ram
name - Sheila
name - Mukesh
name - Rani
Original Spliterator
name - Nick
name - Amy
name - Desi
name - Margo

Here you are splitting the spliterator make sure to check that splitting actually happened by checking for null.

Here note one thing, according to Java docs -

If the original thread hands a spliterator off to another thread for processing, it is best if that handoff occurs before any elements are consumed with tryAdvance(), as certain guarantees (such as the accuracy of estimateSize() for SIZED spliterators) are only valid before traversal has begun.

So make sure you first do the splitting then only start any operation on the elements.

You can split a spliterator into many partitions, if it can’t be split further null would be returned.

See an example here -

 static <T> void parEach(TaggedArray<T> a, Consumer<T> action) {
   Spliterator<T> s = a.spliterator();
   long targetBatchSize = s.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() * 8);
   new ParEach(null, s, action, targetBatchSize).invoke();
 }

 static class ParEach<T> extends CountedCompleter<Void> {
   final Spliterator<T> spliterator;
   final Consumer<T> action;
   final long targetBatchSize;

   ParEach(ParEach<T> parent, Spliterator<T> spliterator,
           Consumer<T> action, long targetBatchSize) {
     super(parent);
     this.spliterator = spliterator; this.action = action;
     this.targetBatchSize = targetBatchSize;
   }

   public void compute() {
     Spliterator<T> sub;
     while (spliterator.estimateSize() > targetBatchSize &&
            (sub = spliterator.trySplit()) != null) {
       addToPendingCount(1);
       new ParEach<>(this, sub, action, targetBatchSize).fork();
     }
     spliterator.forEachRemaining(action);
     propagateCompletion();
   }
 }

That's all for this topic Spliterator in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!

Referrence - https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html


Related Topics

  1. Stream API in Java 8
  2. Java Stream API Examples
  3. Primitive type streams in Java Stream API
  4. Collecting in Java Stream API
  5. Lambda expressions in Java 8

You may also like -

>>>Go to Java advance topics page

Monday, 16 January 2017

FlatMap in Java

If you know about the mapping operation in Java stream, in mapping operation the given function is applied to all the elements of the stream.

Where as flattening a structure, in simple terms, means bringing all the nested structures at the same level. If you have a data structure with many nested levels flattening will break all the nested levels and bring all the elements at the same level.

As example if you have a list of Strings, list<String> like - [[“a”, “b”, “c”], [“c”, “d”], [“c”, “e”, “f”]] then flattening it will bring everything to the same level and the structure you will have be like this -

[“a”, “b”, “c”, “c”, “d”, “c”, “e”, “f”].

Bringing them both together in a method flatMap() means, function will be applied to all the elements of the stream and then it will be flatten to have a single level structure.

FlatMap example

Let’s say there is a class called Order which has a collection of items. If you have a stream of orders you can get a stream containing all the items in all the orders like this -

Order class

public class Order {
    private String orderId;
    private List<String> items;
    public String getOrderId() {
        return orderId;
    }
    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }
    public List<String> getItems() {
        return items;
    }
    public void setItems(List<String> items) {
        this.items = items;
    }
}

Getting a stream containing all the items in all the orders

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class FlatMapDemo {

    public static void main(String[] args) {
        List<Order> orderList = getOrderList();
        Stream<String> item = orderList.stream().flatMap(order -> order.getItems().stream());
        item.forEach(System.out::println);
    }
    
    /**
     * 
     * @return
     */
    private static List<Order> getOrderList(){
        List<Order> orderList = new ArrayList<Order>();
        Order order = new Order();
        order.setOrderId("1");
        order.setItems(Arrays.asList("Item1", "Item2", "Item3"));
        orderList.add(order);
        order = new Order();
        order.setOrderId("2");
        order.setItems(Arrays.asList("Item3", "Item5"));
        orderList.add(order);
        return orderList;
    }
}

Output

Item1
Item2
Item3
Item3
Item5

Here you can see using flatMap() you are getting all the items which are stored as a list inside orders.

Methods for primitive data types

In Java stream API there are variants of flatMap method which work with primitive data types. These methods are -

  • flatMapToInt() - Works with int data type. Returns a new IntStream.
  • flatMapToLong() - Works with long data type. Returns a new LongStream.
  • flatMapToDouble() - Works with double data type. Returns a new DoubleStream.

flatMapToInt example

If you have 2D array and you want to flatten it and get a new IntStream you can get it like this -

int[][] numArray = {{1, 2}, {3, 4}, {5, 6}};
Stream<int[]> numStream = Stream.of(numArray);
IntStream iStream = Stream.of(numArray).flatMapToInt(n -> Arrays.stream(n));
iStream.forEach(System.out::println);

Output

1
2
3
4
5
6

In the lambda expression n -> Arrays.stream(n), n denotes one of the array with in the 2D array, so first time {1,2} will be passed as the mapped stream and its contents will be placed in the new IntStream, next time another array {3,4} will be passed and so on.

That's all for this topic FlatMap in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Collecting in Java Stream API
  2. Reduction Operations in Java Stream API
  3. Parallel Stream in Java Stream API
  4. Java Stream API Examples
  5. Primitive type streams in Java Stream API
  6. Method reference in Java 8

You may also like -

>>>Go to Java advance topics page

Friday, 13 January 2017

Collecting in Java Stream API

Collect method is used to perform a mutable reduction operation on the element of the given stream.

A mutable reduction operation can be defined as an operation that accumulates input elements into a mutable result container, such as a Collection or StringBuilder, as it processes the elements in the stream. In simple way you can say collect methods are used to get a collection from the stream.

Note that this is a terminal operation.

collect method

There are two variants of collect() method -

  1. <R,A> R collect(Collector<? super T,A,R> collector) - Performs a mutable reduction operation on the elements of this stream using a Collector.
    • R - the type of the result
    • A - the intermediate accumulation type of the Collector
    • T – Element type of the stream
    • collector – Instance of the Collector interface

    Collector interface

    public interface Collector<T,A,R>
    

    A Collector is specified by four functions that work together to accumulate entries into a mutable result container, and optionally perform a final transform on the result. They are:

    • creation of a new result container (supplier())
    • incorporating a new data element into a result container (accumulator())
    • combining two result containers into one (combiner())
    • performing an optional final transform on the container (finisher())

    Collectors Class

    Collector class, an implementation of Collector interface implements various useful reduction operations (as static methods), such as accumulating elements into collections, summarizing elements according to various criteria, etc.

    These are the methods you will generally use rather than implementing Collector interface yourself.

    Examples using the predefined collectors

    For these examples Employee class will be used -

    Employee class

    class Employee {
        private String empId;
        private int age;
        private String name;
     private char sex;
        private int salary;
     Employee(String empId, int age, String name, char sex, int salary){
      this.empId = empId;
      this.age = age;
      this.name = name;
      this.sex = sex;
      this.salary = salary;
     }
     public String getEmpId() {
      return empId;
     }
     public void setEmpId(String empId) {
      this.empId = empId;
     }
     public int getAge() {
      return age;
     }
     public void setAge(int age) {
      this.age = age;
     }
     public String getName() {
      return name;
     }
     public void setName(String name) {
      this.name = name;
     }
     public char getSex() {
      return sex;
     }
     public void setSex(char sex) {
      this.sex = sex;
     }
     public int getSalary() {
      return salary;
     }
     public void setSalary(int salary) {
      this.salary = salary;
     } 
    }
    
    1. If you want a list having names of all the employees you can use the toList method of the Collectors class.

      List<String> nameList = empList.stream().map(Employee::getName).collect(Collectors.toList());
      
    2. If you want to store the names in the set.
      Set<String> nameSet = empList.stream().map(Employee::getName).collect(Collectors.toSet());
      
    3. If you want to specify the collection yourself, as example you want the name to be stored in sorted order and want to use TreeSet for the purpose.
      Set<String> nameSet = empList.stream().map(Employee::getName).collect(Collectors.toCollection(TreeSet::new));
      
    4. If you want to store data in a Map so that empId is the key and name is the value.
      Map<String, String> nameMap = empList.stream().collect(Collectors.toMap(Employee::getEmpId, Employee::getName));
      
    5. If you want all the names as a String, joined by comma
      String names = empList.stream().map(Employee::getName).collect(Collectors.joining(","));
      
    6. If you want total salary given to all the employees -
      int totalSalary = empList.stream().collect(Collectors.summingInt(Employee::getSalary));
      
    7. If you want to group the employees by sex -
      Map<Character, List<Employee>> empMap = empList.stream().collect(Collectors.groupingBy(Employee::getSex));
      
      There is also a groupingByConcurrent method which should be used with parallelStream, see example here Parallel Stream in Java Stream API.
    8. In case function is a Predicate, i.e. returns a boolean-valued function it is more efficient to use partitioningBy rather than groupingBy. As Example if you want to partition by employees getting salary greater than or equal to 8000.
      Map<Boolean, List<Employee>> empMap = empList.stream().collect(Collectors.partitioningBy(e -> e.getSalary() >= 8000 ));
      

    There are also methods like summarizingInt, summarizingDouble and summarizingLong that provide summary statistics, see an example in Java stram example.

  2. Another variation of the collect method -
    <R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)
    
    • supplier - a function that creates a new result container.
    • accumulator - function for adding an element into a result.
    • combiner - function for combining two partial result.

    As example – If you want to accumulate strings into an ArrayList -

    List<String> asList = Stream.of("a", "b", "c").collect(ArrayList::new, 
    ArrayList::add, ArrayList::addAll);
    
    If you prefer using lambda expressions instead of method reference then you can write the same thing as -
    asList = Stream.of("a", "b", "c").collect(() -> new ArrayList<>(), (alist, word) -> alist.add(word), (alist1, alist2) -> alist1.addAll(alist2));
    

    Here you can see first param is creating a new result container (a new ArrayList), second param is a function for adding element to the result and third is combining two partial results.

That's all for this topic Collecting in Java Stream API. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Stream API in Java 8
  2. Reduction Operations in Java Stream API
  3. Parallel Stream in Java Stream API
  4. Map operation in Java Stream API
  5. Lambda expressions in Java 8

You may also like -

>>>Go to Java advance topics page

Wednesday, 11 January 2017

Map operation in Java Stream API

Map operations, as the name suggests, are used to do the element mapping from one stream to another. Map operation will return a stream consisting of the results of applying the given function to the elements of this stream. So, whatever function is provided is applied on all the elements of the stream.

One thing to here is; since new stream is returned map operation is an intermediate operation.

map method

Java stream API provides a map method -

<R> Stream<R> map(Function<? super T,? extends R> mapper) - Returns a stream consisting of the results of applying the given function to the elements of this stream.

Here R is the element type of the new stream, T denotes the element type of the existing stream and mapper is the function which will be applied to all the elements of the stream.

Here note that mapper is an instance of Function which is a functional interface. Since it is a functional interface therefore it can be used as the assignment target for a lambda expression or method reference.

Mapping examples in Java Stream

  1. You have a stream of some names and you want to get a list where names are stored in upper case. In that case using map() method you can apply a function to all the elements of the stream to convert those elements to upper case and then using collector, collect them in a list.
    public class MappingDemo {
    
        public static void main(String[] args) {
            List<String> nameList = Stream.of("amy", "nick", "margo", "desi")
                  .map(s->s.toUpperCase()).collect(Collectors.toList());
            System.out.println("Names in upper case" + nameList);
    
        }
    
    }
    

    Output

    Names in upper case[AMY, NICK, MARGO, DESI]
    
  2. You have a list of salaries and you want to increase salaries by 10%.
    List<Integer> myList = Arrays.asList(7000, 5000, 4000, 24000, 17000, 6000);  
    myList.stream().map(i -> (i+ (i * 10/100))).forEach(System.out::println);
    

    Output

    7700
    5500
    4400
    26400
    18700
    6600
    
  3. There is an employee class and you want the name of all the female employees.
    public class MappingDemo {
    
        public static void main(String[] args) {
            MappingDemo md = new MappingDemo();
            List<Employee> empList = md.createList();
            System.out.println("--- Name of female employees ---");
            empList.stream().filter(e -> (e.getSex() == 'F'))
                       .map(e -> e.getName()).forEach(System.out::println);
    
        }
        
        // Stub method to create list of employee objects
        private List<Employee> createList(){
            List<Employee> empList = Arrays.asList(new Employee("E001", 40, "Ram", 'M', 5000), 
                                           new Employee("E002", 35, "Sheila", 'F', 7000), 
                                           new Employee("E003", 24, "Mukesh", 'M', 9000), 
                                           new Employee("E004", 37, "Rani", 'F', 10000));
            
            return empList;
        }
        class Employee {
            private String empId;
            private int age;
            private String name;
            private char sex;
            private int salary;
            Employee(String empId, int age, String name, char sex, int salary){
                this.empId = empId;
                this.age = age;
                this.name = name;
                this.sex = sex;
                this.salary = salary;
            }
            public String getEmpId() {
                return empId;
            }
            public void setEmpId(String empId) {
                this.empId = empId;
            }
            public int getAge() {
                return age;
            }
            public void setAge(int age) {
                this.age = age;
            }
            public String getName() {
                return name;
            }
            public void setName(String name) {
                this.name = name;
            }
            public char getSex() {
                return sex;
            }
            public void setSex(char sex) {
                this.sex = sex;
            }
            public int getSalary() {
                return salary;
            }
            public void setSalary(int salary) {
                this.salary = salary;
            } 
            
        }
    
    }
    

    Output

    --- Name of female employees ---
    Sheila
    Rani
    

Variants of map() method

There are three variants of map() method which return a primitive stream.

  • mapToInt(ToIntFunction<? super T> mapper) - Returns an IntStream consisting of the results of applying the given function to the elements of this stream.
  • mapToDouble(ToDoubleFunction<? super T> mapper) - Returns a DoubleStream consisting of the results of applying the given function to the elements of this stream.
  • mapToLong(ToLongFunction<? super T> mapper) - Returns a LongStream consisting of the results of applying the given function to the elements of this stream.

Apart from that, in all the primitive type streams – IntStream, LongStream and Double Stream there is also a mapToObj() method.

For IntStream mapToObj() function os defined like this -

  • mapToObj(IntFunction<? extends U> mapper) - Returns an object-valued Stream consisting of the results of applying the given function to the elements of this stream.

Code examples

  1. If you want to get the total of salaries for the employees (Using the employee class as above) -
    int totalSalary = empList.stream().mapToInt(e -> e.getSalary()).sum();
    System.out.println("total of salaries " + totalSalary);
    

    Output

    total of salaries 31000
    
  2. If you want to get the maximum salary -
    OptionalInt maxSalary = empList.stream().mapToInt(e -> e.getSalary()).max();
    if(maxSalary.isPresent()){
        System.out.println("Maximum Salary " + maxSalary.getAsInt());
    }
    

    Output

    Maximum Salary 10000
    
  3. For your testing you want to create 500 objects of some class -
    List<Employee> empList = IntStream.rangeClosed(1, 500).mapToObj(Employee::new).collect(Collectors.toList());
    

That's all for this topic Map operation in Java Stream API. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Stream API in Java 8
  2. Parallel Stream in Java Stream API
  3. Java Stream API Examples
  4. Reduction Operations in Java Stream API
  5. Lambda expressions in Java 8

You may also like -

>>>Go to Java advance topics page

Monday, 9 January 2017

Primitive type streams in Java Stream API

If you have gone through the post Stream API in Java 8 one thing you would have noticed is that Streams work on object references. They can’t work on primitive types because of that many times people use Stream<Integer>, Stream<Long> or Stream<Double> in order to wrap primitive types into a wrapper object.

In Java Stream API Examples you will see an example where integers are collected in Stream<Integer>. But, that is not an efficient way to work with primitive types as you need to wrap them into wrapper objects. Instead you should use primitive specializations of Stream like IntStream, LongStream, and DoubleStream that can store primitive values.

Apart from int you can use IntStream for short, char, byte, and boolean. For float DoubleStream can be used.

Creating primitive type Streams

  1. You can use of() method to create primitive type Stream. It has two variants, for IntStream these two variants are -
    • static IntStream of(int t) - Returns a sequential IntStream containing a single element.
    • static IntStream of(int... values) - Returns a sequential ordered stream whose elements are the specified values.

    As Example -

    System.out.println("--- IntStream ---");
    IntStream is = IntStream.of(3, 4, 5, 6);
    is.forEach(System.out::println);
    

    Output

    --- IntStream ---
    3
    4
    5
    6
    

    It works the same way for LongStream and DoubleStream.

  2. Using Arrays.stream() method

    It has two variants. For DoubleStream these two variants are -

    • public static DoubleStream stream(double[] array) - Returns a sequential DoubleStream with the specified array as its source.
    • public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) - Returns a sequential DoubleStream with the specified range of the specified array as its source.

    It works the same way for IntStream and LongStream.

    Example of Arrays.stream()

    System.out.println("--- DoubleStream ---");
    double[] num = {3.0, 4.7, 5.2, 6.8};
    DoubleStream numStream = Arrays.stream(num);
    numStream.forEach(System.out::println);
    System.out.println("--- With Specified range ---");
    numStream = Arrays.stream(num, 0, 2);
    numStream.forEach(System.out::println);
    

    Output

    --- DoubleStream ---
    3.0
    4.7
    5.2
    6.8
    --- With Specified range ---
    3.0
    4.7
    

    In the second variant since second argument is 2 and the end index passed is exclusive so effective range for the stream is 0 – 1.

  3. Using range() and rangeClosed() methods
    • static IntStream range(int startInclusive, int endExclusive) - Returns a sequential ordered IntStream from startInclusive (inclusive) to endExclusive (exclusive) by an incremental step of 1.
    • static IntStream rangeClosed(int startInclusive, int endInclusive) - Returns a sequential ordered IntStream from startInclusive (inclusive) to endInclusive (inclusive) by an incremental step of 1.

    It works the same way for LongStream. Note that these methods will work with IntStream and LongStream, not provided for DoubleStream.

    As example – If you want a stream with 1000 integers, 1 – 1000.

    IntStream thousandInt = IntStream.rangeClosed(1, 1000);
    

    Since you can create a range of numbers, these methods help with testing with large data. See an example in Parallel Stream in Java Stream API.

Transforming Stream to primitive type Stream

Stream interface provides methods mapToInt, mapToDouble and mapToLong that can be used to transform stream of objects to a stream of primitive types.

Infact reduction operations such as average, sum, min (without specifying a comparator), max (without specifying a comparator) are not provided for Stream with object references. Since these operations are used quite frequently with streams so you will do this transformation using mapToxxx methods a lot if time.

As example – If you have a list of employee objects and you want to get the maximum salary you can do it using mapToInt method like this -

OptionalInt maxSalary = empList.parallelStream().mapToInt(e -> e.getSalary()).max();

If you want total amount given to all employees then you can sum the salaries like this -

int totalSalary = empList.parallelStream().mapToInt(e -> e.getSalary()).sum();

If you have noticed the first example returns the result of type OptionalInt. Methods that return result of type Optional in Stream with objects will return result of type OptionalInt, OptionalLong and OptionalDouble. In these classes there are specific methods like getAsInt(), getAsLong() and getAsDouble() rather than a generic get() method present in Optional class.

Transforming primitive type Stream to Stream of objects

All the primitive type Streams have boxed() method that will return a Stream consisting of the elements of this stream wrapped as object.

Thus used with DoubleStream, boxed() method will return a Stream consisting of the elements of this stream, each boxed to a Double i.e. Stream<Double>.

Same way for IntStream and LongStream you will get a Stream having elements of type Integer and Long respectively, i.e. Stream<Integer> and Stream<Long>.

As example -

Stream<Integer> iStream = IntStream.of(3, 4, 5, 6).boxed();

That's all for this topic Primitive type streams in Java Stream API. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Stream API in Java 8
  2. Reduction Operations in Java Stream API
  3. Lambda expressions in Java 8
  4. Method reference in Java 8
  5. Functional interface annotation in Java 8

You may also like -

>>>Go to Java advance topics page

Wednesday, 4 January 2017

Parallel Stream in Java Stream API

You can execute streams in serial or in parallel. When a stream executes in parallel, the Java runtime partitions the stream into multiple sub-streams. Aggregate operations iterate over and process these sub-streams in parallel and then combine the results.

This parallel execution of data, with each sub-stream running in a separate thread, will result in increase in performance. Since, part of the data (sub-stream) is processed by different processors of multi-core processors in separate threads which are later combined to give the final result, bulk operations can also be processed in less time making the whole process more efficient and less time consuming.

Since partial results are computed by separate threads and later combined so it becomes important to think about these points -

  1. Is separate combiner needed to combine partial results or aggregate function itself can work as combiner too.
  2. Since multi-threading is involved so any shared variable should not be updated by any operation in the parallel stream.
  3. Most of the time collection is used as a data source of the stream and collections are not thread safe. Which means that multiple threads cannot manipulate a collection without introducing thread interference errors.
  4. Parallel stream uses common fork-join thread pool. Thus, running a performance intensive long running task may block all threads in the pool, which may block all other tasks (as no threads will be available) that are using parallel streams.
  5. Note that parallelism is not automatically faster than performing operations serially, although it can be if you have enough data and processor cores. While aggregate operations enable you to more easily implement parallelism, it is still your responsibility to determine if your application is suitable for parallelism.

How to get a parallel stream

Collection has methods Collection.stream() and Collection.parallelStream(), which produce sequential and parallel streams respectively.

You can also call parallel() method on a sequential stream to get a parallel stream. The parallel() method is defined in the BaseStream interface.

As example: If you have an Employee class and for some testing you want to create 1000 objects of Employee class then you can use parallel() method with range -

List<Employee> empList = IntStream.rangeClosed(1, 1000).parallel().mapToObj(Employee::new).collect(Collectors.toList());

Examples using parallel stream

Let’s first see a simple example using parallel stream where you need to find the employee with maximum salary.

Employee class

public class Employee {
    private String lastName;
    private String firstName;
    private String empId;
    private int age;
    private int salary;
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getEmpId() {
        return empId;
    }
    public void setEmpId(String empId) {
        this.empId = empId;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
    public String getFullName(){
     return this.firstName + " " + this.lastName;
    }
   
    public int getSalary() {
 return salary;
    }
    public void setSalary(int salary) {
 this.salary = salary;
    }
}

Using parallel stream

import java.util.ArrayList;
import java.util.List;
import java.util.OptionalInt;

public class ParallelDemo1 {

    public static void main(String[] args) {
        // getting list of employee 
        List<Employee> empList = createList();
        OptionalInt maxSalary = empList.parallelStream().mapToInt(e -> e.getSalary()).max();
        if(maxSalary.isPresent()){
            System.out.println("Max Salary " + maxSalary.getAsInt());
        }
    }
    
    // Stub method to create list of employee objects
    private static List createList(){
        List<Employee> empList = new ArrayList<Employee>();
        Employee emp = new Employee();
        emp.setEmpId("E001");
        emp.setAge(40);
        emp.setFirstName("Ram");
        emp.setLastName("Chandra");
        emp.setSalary(5000);
        empList.add(emp);
        emp = new Employee();
        emp.setEmpId("E002");
        emp.setAge(35);
        emp.setFirstName("Sheila");
        emp.setLastName("Baijal");
        emp.setSalary(7000);
        empList.add(emp);
        emp = new Employee();
        emp.setEmpId("E003");
        emp.setAge(24);
        emp.setFirstName("Mukesh");
        emp.setLastName("Rishi");
        emp.setSalary(9000);
        empList.add(emp);
        emp = new Employee();
        emp.setEmpId("E004");
        emp.setAge(37);
        emp.setFirstName("Rani");
        emp.setLastName("Mukherjee");
        emp.setSalary(10000);
        empList.add(emp);
        return empList;
    }
}

Output

Max Salary 10000

Mistake of updating a shared variable

As already stated above updating a shared state when using parallel stream may cause problem due to multi-threading. Let’s see it with an example.

There is an Employee class and 500 objects of the Employee class are stored in a list. Then using parallel stream you are trying to get the total salary paid to all employees.

Employee class

Employee class is same as used above with one difference, now there is a constructor with int argument which is used to set salary property. Using range method 500 objects will be created with salary set as 1..500.

public class Employee {
    private String lastName;
    private String firstName;
    private String empId;
    private int age;
    private int salary;
    
    Employee(int salary){
     this.salary = salary;
    }
    
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getEmpId() {
        return empId;
    }
    public void setEmpId(String empId) {
        this.empId = empId;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
    public String getFullName(){
     return this.firstName + " " + this.lastName;
    }
   
    public int getSalary() {
  return salary;
    }
}

Total Salary Calculation

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class ParallelDemo {

    public static void main(String[] args) {
        Salary sal = new Salary();
        List<Employee> empList = createList();
        empList.parallelStream().forEach(sal::doProcess);
        
        System.out.println("Total - " + sal.getTotalSalary());

    }
    // Stub method to create list of employee objects
    private static List createList(){
        List<Employee> empList = IntStream.rangeClosed(1, 500).mapToObj(Employee::new).collect(Collectors.toList());
        return empList;
    }
}

class Salary{
    private int total = 0;
    
    public void doProcess(Employee emp){
        addSalary(emp.getSalary());
    }
    
    public void addSalary(int salary){
        total = total + salary;
    }
    public int getTotalSalary(){
        return total;
    }
}

Output

Total – 113359, Total – 125250, Total – 120901, Total – 123835, Total – 125250

I got these 5 outputs on executing it 5 times. You can see that output is different (Correct output is 125250 by the way). It is because total is changed from the parallel stream which is a shared variable.

If you have seen the first example I have given for parallel stream you must have got an idea what’s the better way to do it.

public class ParallelDemo {

    public static void main(String[] args) {
        Salary sal = new Salary();
        List<Employee> empList = createList();
        //empList.parallelStream().forEach(sal::doProcess);
        int totalSalary = empList.parallelStream().mapToInt(e -> e.getSalary()).sum();
        sal.addSalary(totalSalary);
        System.out.println("Total - " + sal.getTotalSalary());

    }
    // Stub method to create list of employee objects
    private static List createList(){
        List<Employee> empList = IntStream.rangeClosed(1, 500).mapToObj(Employee::new).collect(Collectors.toList());
        return empList;
    }
}

Here note that you are not changing the shared variable in the stream. You are getting the salaries of the employees and summing it. That way, even in parallel stream there is no problem as different threads are getting different data to add and then those partial results are combined to get the total salary.

Using Collectors.groupingByConcurrent

Operation groupingBy performs poorly with parallel streams. (This is because it operates by merging two maps by key, which is computationally expensive). With parallel stream you should use groupingByConcurrent operation instead of groupingBy which returns an instance of ConcurrentMap instead of Map.

As example – If you have an Employee class and you want to group employees on the basis of sex it can be done as -

import java.util.Arrays;
import java.util.List;

import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

public class ParallelDemo1 {

    public static void main(String[] args) {
        ParallelDemo1 pd = new ParallelDemo1();
        // getting list of employee 
        List<Employee> empList = pd.createList();
        
        ConcurrentMap<Character, List<Employee>> bySalary = empList.parallelStream().collect(Collectors.groupingByConcurrent(e -> e.sex));
        bySalary.forEach((K, V)->{
            System.out.println("Key- " + K + " Value ");
            V.forEach(v->System.out.println(v.name));
        });
        
    }
    
    
    // Stub method to create list of employee objects
    private List<Employee> createList(){
        List<Employee> empList = Arrays.asList(new Employee("E001", 40, "Ram", 'M', 5000), 
        new Employee("E002", 35, "Sheila", 'F', 7000), 
        new Employee("E003", 24, "Mukesh", 'M', 9000), 
        new Employee("E004", 37, "Rani", 'F', 10000));
        
        return empList;
    }

    class Employee {
        private String empId;
        private int age;
        private String name;
        private char sex;
        private int salary;
        Employee(String empId, int age, String name, char sex, int salary){
            this.empId = empId;
            this.age = age;
            this.name = name;
            this.sex = sex;
            this.salary = salary;
        }
        
    }
}

Output

Key- F Value 
Sheila
Rani
Key- M Value 
Mukesh
Ram

Using forEachOrdered

The order in which a pipeline processes the elements of a stream depends on whether the stream is executed in serial or in parallel.

As example :

Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8 };
List<Integer> listOfIntegers = new ArrayList<>(Arrays.asList(intArray));
System.out.println("listOfIntegers:");
listOfIntegers.stream().forEach(e -> System.out.print(e + " "));

Output

listOfIntegers:
1 2 3 4 5 6 7 8

Here you can see that the pipeline prints the elements of the list listOfIntegers in the order that they were added to the list.

With parallel stream -

System.out.println("Parallel stream");
listOfIntegers.parallelStream().forEach(e -> System.out.print(e + " "));

Output

Parallel stream:
3 4 1 6 2 5 7 8

Here you can see that the pipeline prints the elements of the list in an apparently random order. When you execute a stream in parallel, the Java compiler and runtime determine the order in which to process the stream's elements to maximize the benefits of parallel computing unless otherwise specified by the stream operation.

Using forEachOrdered -

System.out.println("With forEachOrdered:");
listOfIntegers.parallelStream().forEachOrdered(e -> System.out.print(e + " "));

Output

With forEachOrdered:
8 7 6 5 4 3 2 1

Note that the method forEachOrdered is used here, which processes the elements of the stream in the order specified by its source, regardless of whether you executed the stream in serial or parallel. Note that you may lose the benefits of parallelism if you use operations like forEachOrdered with parallel streams.

Points to note

  1. Parallelism is not automatically faster than performing operations serially, although it can be if you have enough data and processor cores.
  2. There is increased overhead of splitting the data, managing multiple threads, combining the partial results.
  3. Make sure that there is enough data for computation that offsets this increased overhead and time saved in parallely processing the data scores over any overhead tasks.
  4. Performance of parallel execution also depends upon the number of processors available.

That's all for this topic Parallel Stream in Java Stream API. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Stream API in Java 8
  2. Java Stream API Examples
  3. Reduction Operations in Java Stream API
  4. Lambda expressions in Java 8

You may also like -

>>>Go to Java advance topics page