Home > Back-end >  Create a Stream<CustomType> using a Stream<String>?
Create a Stream<CustomType> using a Stream<String>?

Time:11-06

Assuming I have a Stream<String>, what is the most succinct way with which I could obtain a Stream<CustomType> where each element of Stream<CustomType> has each element of Stream<String> as value for the one of its member variables:

E.g.:

class CustomType {
    private String id;

    public void setId(String id) {
        this.id = id;
    } 
}

class Test {
    public static void main (String... args) {
        Stream<String> source = Stream.of("A", "B", "C"); 
        
        Stream<CustomType> result = source.map(s -> {
            CustomType obj = new CustomType();
            obj.setId(s);
            return obj;
        });  
    }
}

Is there a way to shorten this?

Later edits: Looking for a way other than overriding constructor of CustomType, and to avoid coding the boilerplate of manually creating CustomType objects CustomType obj = new CustomType(); i.e. somehow have Stream API create CustomType objects for me so I could just specify what setter (e.g.: setID()) the Strings should be set to.

CodePudding user response:

If you can change the constructor for your custom type, you can do:

class CustomType {
    private String id;

    public CustomType(String id) {
      this.id = id;
    }

    public void setId(String id) {
        this.id = id;
    } 
}

class Test {
    public static void main (String... args) {
        Stream<String> source = Stream.of("A", "B", "C");         
        Stream<CustomType> result = source.map(CustomType::new);  
    }
}

If you can't add a new constructor, the best you can do is move the setting logic outside of the stream processor, like so:

class Test {
    public static void main (String... args) {
        Stream<String> source = Stream.of("A", "B", "C");         
        Stream<CustomType> result = source.map(Test::customTypeWithId);  
    }

    private static CustomType customTypeWithId(String id) {
        CustomType obj = new CustomType();
        obj.setId(s);
        return obj;
    }
}

CodePudding user response:

For any CustomType you could do it like this.

  • define a Function to create an instance and set the value;
  • then call the method with the source Stream and that function to return the new Stream

Stream<String> source = Stream.of("A", "B", "C");

Function<String,CustomType> fnc = (str) -> {
        CustomType t = new CustomType();
        t.setId(str);
        return t;};

Stream<CustomType> stream = customStream(source, fnc);
    
public static <T> Stream<T> customStream(Stream<String> source,
        Function<String, T> fnc) {
    Builder<T> builder = Stream.builder();
    source.forEach(k -> builder.add(fnc.apply(k)));
    return builder.build();
}

Of course it would be better if your custom types implemented an interface that had T setId(String s) as the method. Here is an example of that:

interface SetIDInterface<T> {
    public T setId(String s);
}

class CustomType implements SetIDInterface<CustomType> {
    public String id;
    
    public CustomType setId(String id) {
        this.id = id;
        return this;   
    }
}

Stream<String> source = Stream.of("A", "B", "C");
Stream<CustomType> stream = customStream(source, CustomType::new);

    
public static <T extends SetIDInterface<T>> Stream<T> 
               customStream(Stream<String> source, Supplier<T> sup) {
    Builder<T> builder = Stream.builder();
    source.forEach(k -> builder.add(sup.get().setId(k)));
    return builder.build();
}
  • Related