Skip to content
Advertisement

Java filtering the object list to string array with stream

I have a class like this

public class Host {

  private HTMLToken.TokenType type;
  private StringBuilder content;

  public Host(HTMLToken.TokenType type) {
    this.type = type;
    content = new StringBuilder();
  }


  String contentAsString() {
    return content.toString();
  }

  void addStrig(String x) {
    content.append(x);
  }

  public enum TokenType {
    TAG, TEXT
  }

}

and static function like this

 public static String[] filterLength(List<Host> hostList, int length) {
    return hostList.stream().filter(str -> str.contentAsString().length() > length)
        .toArray(String[]::new);
  }

The problem is inside of filterLength function I can’t return stream as a String array(I want to return content in the Host class) because List holds Host object how can I return as a string in 1 line code?

Advertisement

Answer

Transform each object in stream

You are successfully streaming, filtering, and collecting a bunch of Host objects into an array. But you seem to be asking how to instead collect a string representation of each Host object.

So, you need to add a step to your streaming operations. For each Host object, we want to generate and collect a String object.

Stream#map

To transform from the objects being streamed to a different kind of object, use Stream#map.

Here is an analog of your code, using LocalDate. We transform each filtered LocalDate object to a String object by passing a method reference: LocalDate :: toString.

List < LocalDate > dates = new ArrayList<>( 4 ) ;
dates.add( LocalDate.of( 2022 , Month.JANUARY, 11 ) ) ;
dates.add( LocalDate.of( 2022 , Month.JANUARY, 12 ) ) ;
dates.add( LocalDate.of( 2022 , Month.JANUARY, 13 ) ) ;
dates.add( LocalDate.of( 2022 , Month.JANUARY, 14 ) ) ;

String[] results = 
    dates
    .stream()
    .filter( localDate -> localDate.getDayOfMonth() > 12 )
    .map( LocalDate :: toString )  // 👈 
    .toArray( String[] :: new ) ;

System.out.println( "results = " + String.join( ", " , results ) ) ;

See this code run live at IdeOne.com.

results = 2022-01-13, 2022-01-14

I see you have a contentAsString method. I will guess that method returns the kind of text you want to collect.

So your code should be something like the following, passing method reference Host :: contentAsString to Stream#map.

return 
    hostList
    .stream()
    .filter( str -> str.contentAsString().length() > length )
    .map( host -> Host::contentAsString )  // 👈 Add this step.
    .toArray( String[]::new );

That code is effective but inefficient. No need to execute contentAsString method twice per input. We can fix this by putting the map call first, then filter based on the length of the already-produced string.

return 
    hostList
    .stream()
    .map( host -> Host::contentAsString )  // 👈 Add this step.
    .filter( string -> string.length() > length )  // 👈 Change this step.
    .toArray( String[]::new );
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement