Lambdy na kolekcjach - wybór pola

0

jest sobie kolekcja (kod z baeldung); z której robimy np grupowanie

class BlogPost {
	    String title;
	    String author;
	    BlogPostType type;
	    int likes;
	}

enum BlogPostType {
	    NEWS,
	    REVIEW,
	    GUIDE
	}

List<BlogPost> posts = Arrays.asList( ... );

Map<BlogPostType, List<BlogPost>> postsPerType = posts.stream()
	  .collect(groupingBy(BlogPost::getType));

A teraz, jak zrobić z dynamicznie podawaną nazwą pola?

String  filedName = "author";
Field[] fields = BlogPost .class.getFields();  // sądzę że bez refleksji się nie obejdzie
??? 
Map<String, List<BlogPost>> postsPerType = posts.stream()
	  .collect(groupingBy(  ??? filedName  ));


Np klucze do tej Mapy wg pole.toString()

Ewentualnie łatwiejsza wersja, typ pól jest jednolity

class BlogPost {
	    String title;
	    String author;
	    String type;
	    // int likes;
	}

0

Może mapa getterów? Map<BlogPostType, Function<BlogPost, String>>

1

Patrzę na sygnaturę static <T,K> Collector<T,?,Map<K,List<T>>> groupingBy(Function<? super T,? extends K> classifier) i widzę że przyjmuje funkcję więc chyba wystarczy sobie dobrą funkcję napisać jak
object -> dynamicznyGetterDoWyciaganiaWartosciPoNazwiePola(nazwaPola, object). Czyli konkretniej można by spróbować:

final Field field = BlogPost .class.getField(nameOfField);
final Map<Object, List<BlogPost>> postsPerType = posts.stream().collect(groupingBy(object -> field.get(object));
1

https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html
static <T,K> Collector<T,?,Map<K,List<T>>
groupingBy(Function<? super T,? extends K> classifier)
Returns a Collector implementing a "group by" operation on input elements of type T, grouping elements according to a classification function, and returning the results in a Map.

custom collector in Java 8
https://blog.indrek.io/articles/creating-a-collector-in-java-8/
https://www.nurkiewicz.com/2014/07/introduction-to-writing-custom.html
https://en.paradigmadigital.com/dev/java-8-how-to-implement-a-collector/

IMHO dalej już jak z własnym komparatorem przy sortowaniu (jakiś własny comparator chyba każdy pisał, nie collector to co inengo).

1

Serio potrzebujesz dynamicznie (po nazwie pola)? To raczej oznaka, że coś bardzo dziwnego robisz, ewentualnie czas zacząć pisać w JavaSkrypcie.
Jakkolwiek:
W tej sytuacji najprościej Ci będzie użyć commons lang np. https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/reflect/FieldUtils.html#readField-java.lang.Object-java.lang.String-

1
Map<BlogPostType, Function<BlogPost, String>> mappers = Map.of(
    "title", BlogPost::getTitle,
   ...
);
String  filedName = "author";
Map<String, List<BlogPost>> postsPerType = posts.stream()
      .collect(groupingBy(  mappers.get(fieldName)  ));

Refleksji bym unikał, bo jak ktoś dołoży pole, do którego nie powinno być dostępu to może o tym zapomnieć.

1 użytkowników online, w tym zalogowanych: 0, gości: 1