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 );