Skip to main content

Posts

Showing posts from November 9, 2018

Java 8 - Streams - How to Create a Stream?

Greetings! It is easy to guess that we can create a Stream using a collection. Actually it is one of the ways to create a Stream. Stream from collections Stream<Employee> stream = employees.stream(); Stream from values Using static Stream.of() we can create a stream using given values. Stream<String> countryStream = Stream.of("Sri Lanka", "India", "Pakistan"); Stream<Integer> integerStream = Stream.of(1, 2, 3); Stream<Employee> employeeStream = Stream.of(new Employee()); Stream from arrays Arrays class has Arrays.stream() static method to convert given array into a stream. int[] intArray = { 1, 2, 3, 4, 5 }; IntStream intStream = Arrays.stream(intArray); String[] stringArray = { "Hello", "World" }; Stream<String> stringStream = Arrays.stream(stringArray); Stream from files Files class has static methods to open a file as a stream. // from a file try (Stream<String> linesStr

Java 8 - Streams - Replace Traditional for Loops

Greetings! It is very common to have numeric iterations like below; for (int i = 1; i <= 100; i++) { // do something } Java 8 has static methods for this common task in IntStream and LongStream. IntStream intStream = IntStream.rangeClosed(1, 100); // Inclusive. Up to 100: 1, 2, ..., 99, 100 IntStream.rangeClosed(1, 100).forEach(System.out::println); // Exclusive. Up to 99: 1, 2, ..., 98, 99 IntStream.range(1, 100).forEach(System.out::println); // With Steps: 1, 2, ..., 98, 100 IntStream.iterate(0, i -> i + 2).limit(50).forEach(System.out::println); Note that iterate produces an infinite stream.

Java 8 - Streams - Numeric Streams

Greetings! It is common to have numeric operations min, max, sum in our code. Stream interface have min and max methods but doesn't have sum method because it make no sense to have it. Even though we can have sum operation using reduce() it has unboxing cost. This is same for min, max operations. Considering those factors, Stream API provides separate interfaces for primitives. IntStream, LongStream and DoubleStream. Convert to numeric stream stream.mapToInt() - return IntStream stream.mapToLong() - return LongStream stream.mapToDoulbe() - return DoubleStream IntStream intStream = stream.mapToInt() Convert back to stream of objects numericStream.boxed() String<Integer> = intStream.boxed() Optional values For primitive operations Optional also have corresponding primitive optionals. OptionalInt, OptionalLong, OptionalDouble There are corresponding functional interfaces like IntPredicate, IntConsumer, IntUnaryOperator for numeric operations. Exa

Java 8 - Streams - sum()

Greetings! Let's say we want to calculate total marks for a student for all subjects. public class Subject { private String name; private Integer marks; } int totalMarks = subjects.stream().map(Subject::getMarks).sum(); This is not working because stream doesn't have sum() operation. That make sense because stream is generic and it doesn't have any meaning for total (sum) operation for an object. And also if we use Integer, behind the scene it will covert to int (unboxing). For a large data set this will be a costly operation. So, to get our desired result we to need to convert our stream into IntStream which offers the sum operation. int totalMarks = subjects.stream().mapToInt(Subject::getMarks).sum(); mapToInt - this intermediate operation returns IntStream

Java 8 - Streams - Terminal Operations

Greetings! Terminal operations are used to close the stream and generate a result. This is the last operation in a stream pipeline hence eagerly executed. Can return concrete value types like (Integer, String, List, Optional), primitive value (int, long) or void. Ex:- forEach, collect, count, anyMatch, nonMatch, allMatch, findAny, findFirst, reduce, min, max, sum are terminal operations. Let's use employee data set for all operations. ( Complete code is here ) public class Employee { enum Gender { MALE, FEMALE }; private String name; private int age; private Gender gender; private Employee(String name, int age, Gender gender) { this.name = name; this.age = age; this.gender = gender; } public static Employee newInstance(String name, int age, Gender gender) { return new Employee(name, age, gender); } // getters } private static List<Employee> employees = Arrays.asList(

Java 8 - Streams - Intermediate Operations

Greetings! Intermediate operations are used to transform the stream into another. These operations can be chained and merge internally as necessary. Lazily process and process only when a terminal operations is called. Ex:- map, flatMap, filter, distinct, limit, skip, sorted are intermediate operations Note that forEach is a terminal operation which close the stream. map() Convert the iteration element into another. public static void main(String[] args) { List<String> countries = Arrays.asList("Sri Lanka", "India", "Pakistan", "England", "Australia"); countries.stream().map(String::toUpperCase).forEach(System.out::println); countries.stream().map(country -> { // create any object and return int length = country.length(); return "Length of ".concat(country).concat(" string is ").concat(String.valueOf(length)); }).forEach(System.out::println); } fil

Java 8 - Streams - Introduction

Greetings! Let's have a look at below code. List<String> countries = Arrays.asList("Sri Lanka", "India", "Pakistan", "England", "Australia"); for (String country : countries) { if (country.length() > 7) { String upperCase = country.toUpperCase(); System.out.println(upperCase); } } This code has several problems. Process sequentially. Difficult to process parallel. Complex codes. Instruct how to do it, not what to do. External loop. (developer has to create the loop). To overcome these kind of problems and get the maximum from multi-core processors Java 8 introduces Stream API. The same code can be re-written using stream as below. countries.stream() .filter(country -> country.length() > 7) .map(country -> country.toUpperCase()) .forEach(System.out::println); As you can see it works like builder pattern. We chain several operations using a d

Java 8 - Constructor References

Greetings! This is same as the method references, except the method name is new. Class::new When we have multiple constructors which constructor will be selected? It depends on the context. (firstName) -> new User(firstName) => User::new (firstName, lastName) -> new User(firstName, lastName) => User::new This can also be used with arrays with exact one parameter. n -> new int[n] int[]::new This helps to create arrays with generic types. Object[] array = stream.toArray(); User[] users = stream.toArray(User[]::new);

Java 8 - Method References

Greetings! In Java we have object references. We pass objects around. What if we can pass reference to a method? In Java 8 if we are executing only one method we can do this using lambda expressions. For an example these are equal.          (x) -> System.out.print(x) System.out::print As you can see, :: separates the name of the method from the class/ object. There are 3 ways we can use method references. object::method - object.method(parameters) Class::staticMethod - Class.staticMethod(parameters) Class::instanceMethod - firstParameter.method(parameters) In first 2 cases, parameters become the methods parameters. As you can see in System.out::print. If we have more than 1 parameters it is still same, (x, y) -> Math.pow(x, y) Math::pow Third case is different. First parameter becomes the target object of the method and rest become the parameters. For example, // (object, arguments) -> object.method(arguments) name -> name.toUpperCase() String::toUpp

Java 8 - Functional Interfaces

Greetings! Functional interface is an interface which has only one abstract method. Runnable, Comparable, ActionListener are few existing examples. interface with only one abstract method. You can have many methods in the interface but should have only one abstract method. To ensure that an interface has only one abstract method, Java8 comes with @FunctionalInterface annotation. It is not mandatory to have this, but with this compiler warns you when you break the contract. We can avoid inner classes' and use lambda expression in place of these interfaces. For an example we can create a thread like this; Thread thread = new Thread(() -> System.out.println("Hello functional interface")); thread.start(); Let's say we have fruits names and we need to print them according to given condition. With prior to Java 8, we can do it like this; public interface Testable { boolean test(String name); } import java.util.Arrays; import java.util.List;

Java 8 - Lambda Expressions

Greetings! Before Java8, Java is a fully object oriented programming language. While most of the other programming languages introduces functional programming Java was in OOP way. Java8 introduces lot of features and lambdas are the biggest change that happened to the language so far. What is functional programming? It is a programming style that allows to program using expressions. With that we can create instance of a function and assign to a variable, pass functions to methods as arguments. Is OOP not enough? We can do everything without lambda expressions. But it help us to write better readable and maintainable codes. And also it gives us better support of multi-cores. In OOP we are not passing behaviors. We pass objects which have behaviors. In functional programming we can pass behaviors. Benefits of lambda expressions Parallel processing. Enable functional programming. Readable and concise. Syntax A lambda expression has 3 parts. Argument list Arrow t