How to Use Java Streams with Primitive Type

  • Post last modified:December 15, 2022
  • Reading time:4 mins read

Introduction

  • Java supports primitive data type such as byte, short , int, long, double , char, boolean etc. Hence it is one of the reason that Java is not Object Oriented Language.
  • Since release of java 8 developers were excited about Streams API and utilization of its method to write more declarative code with lambda and method chaining.
  • But at the same time developers were curious about how Java will handle the primitive data type with streams.
  • So in this article we will discuss about how we can use Streams API with primitive and what are the current limitation and how to overcome them.

Current Design

  • If you see Stream Interface that provides lot of great features to process elements in a collection, it extends from BaseStream interface.
  • BaseStream Interface is also extended by IntStream, DoubleStream and LongStream Interface.
  • Once you kind of see this design you would immediately know that Java language designed has done some work for handling primitive types as well in order to use features from Streams API.

IntStream

  • Let’s first talk about IntStream. It is an Interface that is designed to handle int primitive data types.
IntStream intStream = IntStream.rangeClosed(1, 10);
  • Now once we get IntStream instance we can perform normal streams api operation like sum, max, forEach, map etc.
  • We can also perform boxing operation on IntStream to convert it to List<Integer> basically List of object type as collections only works with object.
List<Integer> result = IntStream
                .rangeClosed(1, 10)
                .boxed().
                collect(Collectors.toList());
  • Unboxing is also one of the frequent operation that we need to perform in day to day development.
     int[] result1 = result
                .stream()
                .mapToInt(a -> a)
                .toArray();
  • Let’s calculate average age from the array of integer that represents age.
    We can use method of that takes array as argument and convert it into IntStream.
  • Since now we have streams with us we can conveniently use average() method to calculate the average age.
int[] age = {50,20,30,15,60};
OptionalDouble average = IntStream.of(age).average();
System.out.println("average age: "+ average.getAsDouble());
System.out.println("--------");
IntStream ageStream = Arrays.stream(age);
OptionalDouble asDouble = ageStream.average();
System.out.println("average age: "+ average.getAsDouble());
  • Let’s also perform some of the common operation of integers such as Sum , min, max using streams api.
OptionalInt max = IntStream.of(1, 2, 3, 4, 5).max();
System.out.println(max.getAsInt());
System.out.println("--------");

OptionalInt min = IntStream.of(1, 2, 3, 4, 5).min();
System.out.println(max.getAsInt());
System.out.println("--------");

int sum = IntStream.of(1, 2, 3, 4, 5).sum();
System.out.println(sum);
System.out.println("--------");

Conversion

  • Converting one type of object to another type is very common operation in day to day java developer. Basically we have to respect API spec and need to follow return type or argument specification in the code.
  • Often we have to convert one collection type to array of elements. We can also convert IntStream to Array easily using toArray() method again provided by Streams API.
int[] ints = IntStream.of(1, 2, 3, 4, 5).toArray();
System.out.println(Arrays.toString(ints));
System.out.println("--------");
  • Additionally, we can also convert one primitive type to another such as converting from int to long as shown below.
        System.out.println("--------");
        int[] id = {12,345,566,33};
        LongStream longStream = IntStream.of(id).asLongStream();
        longStream.forEach(a-> System.out.println(a));
  • We saw the operations on IntStream, Long and DoubleStream are not very different than IntStream in terms of supported operations.

No Support for Boolean, Char etc.

  • As you can see in the design that we mentioned in the start of article, java only supports IntStream, LongStream and DoubleStream. But what about CharStream, BooleanStream ?
  • I don’t know exactly why Java designer did not add these into Streams, but there are workarounds.
  • Below is the example when i try to perform stream on chars data structure.
  • We can technically still use IntStream to count the number of elements and then for each index we can use mapToObject that converts index to char.
  • Now once we have Stream<Character> we can easily perform Streams API operations such distinct in this case.
Stream<Character> characterStream = IntStream.rangeClosed(0, chars.length - 1).mapToObj(a -> chars[a]);
characterStream.distinct().forEach(a-> System.out.println(a));

Conclusion

  • In this article we discuss about primitive data type and how can we use primitive data type with Java Streams API.
  • Java BaseStreams is extended by Long, Int and Double primitive data types, but for other primitive data types we have certain workarounds.

Bonus Tip

Further Reads

Leave a Reply