Java Programming Tutorials

Java programming tutorials with many code examples!

Java casting trick

Recently I’ve rediscovered Class.cast(object) that can be used to cast objects to a type. In Java 8 streams the method allows to do a nice Java casting trick.

Old C-style casting

I don’t cast types very often. But sometimes it is the only way, especially when working with legacy libraries and/or badly designed API. This way or another, I when I wanted to cast types I did use C-style casting:

Object o = ...;
String name = (String) o;

But it turns out that since Java 5 there is T Class<T>.cast(Object) method that do the same thing:

Object o = ...;
String name = String.cast(o);

I leave it for you to decide which one is better, but with advent of Java 8, method references, and streams the later got a new life!

Casting mapper function

Unlike C-style cast, the method version can be passed as method reference into a stream to cast objects to correct type. Together with Class.isAssignableFrom(Class) we can create a nice object filter function with correct types:

// Bag of different objects:
Collection<Object> items = ...;

List<String> strings = items.stream()
    // Select only Strings:
    .filter(o -> String.isAssignableFrom(o.getClass()))
    // Object -> String
    .map(String::cast)
    // Collect to correctly typed collection:
    .collect(Collectors.toList());

I like that. Method References and Streams bring new life into old methods.

Complete program

Here’s a complete program, which selects objects by their type and returns correctly typed collection:

package com.farenda.java.lang;

import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public class CastingTrick {

    public static void main(String[] args) {
        Collection<Object> bag = Arrays.asList(
                "string 1",
                1,
                "string 2",
                2,
                42d,
                Instant.EPOCH,
                Instant.now()
        );

        System.out.println("Strings: " + selectByType(bag, String.class));
        System.out.println("Numbers: " + selectByType(bag, Number.class));
        System.out.println("Ints:    " + selectByType(bag, Integer.class));
        System.out.println("Times:   " + selectByType(bag, Instant.class));
    }

    static <T> List<T> selectByType(Collection<Object> bag,
                                    Class<T> type) {
        return bag.stream()
                .filter(o -> type.isAssignableFrom(o.getClass()))
                .map(type::cast)
                .collect(Collectors.toList());
    }
}

The program works as works as advertised:

Strings: [string 1, string 2]
Numbers: [1, 2, 42.0]
Ints:    [1, 2]
Times:   [1970-01-01T00:00:00Z, 2017-07-02T10:27:10.962Z]
Share with the World!