简体   繁体   中英

Ordered Collection of key-value Pairs in Java

I have a 2D table with columns: Language and Proficiency , which I need to populate with the input.

I've created a method:

public void typeLanguages(@NotNull List<String> languages,
                          @NotNull List<SkillLevel> skillLevels) {

    if(languages.size() != skillLevels.size()) { throw new IllegalArgumentException(); }

    IntStream.range(0, skillLevels.size()).forEach(i -> {
        typeAndConfirm(languagesFld.get(i), languages.get(i));
        typeAndConfirm(skillFld.get(i), skillLevels.get(i).getLangSkill());
    });
}

IntStream is used, so i -th language-skillLevel pair is inserted in i -th row.

SkillLevel is an enum which implements getLangSkill() method which returns, one of four proficiency levels as String

However, there is a risk that the user can provide Lists of different sizes ( although guarded ) or that they could mix up the order and give themselves the wrong proficiency scores.

AFAIK there are no tuples in Java. I tried using Map, but I can't see any method that could let me use i -th element of map.

Don't misuse Collections

The two pieces of data: language and level don't a have any value separately, only when you have them both they are useful. That means they have to constitute an object . An attempt to utilize a Map just for the purpose of describing the relationship between the two properties would be an abuse of collection, which would result in unmaintainable code.

So instead of maintaining the two separate lists, which makes your code brittle, you can define arecord ( or a class if you want it to be mutable or using a version earlier than Java 16 ) that will combine both properties into a single object:

public record LanguageLevel(String language, SkillLevel level) {}

With that instead of List<String> and List<SkillLevel> you will deal with a List<LanguageLevel> .

In case if you would want to sort the objects in a list and there's only one particular way of sorting that makes sense in your application - so called natural order , then you can make LanguageLevel implement Comparable interface.

But if in your domain model, these pairs have no natural order , and they might be sorted differently depending on a situation that have a look at the Comparator interface.

You can define multiple comparators to facilitate different ways of sorting. For example:

Comparator<LanguageLevel> bySkillDescAndByLang = 
    Comparator.comparing(LanguageLevel::level).reversed() // assumption that SkillLevel implements Comparable<SkillLevel>
        .thenComparing(LanguageLevel::language);

List<LanguageLevel> languages = // initialize the list
languages.sort(bySkillDescAndByLang);

Either:

  • Use a NavigableMap such as TreeMap
  • Define a record (a nominal tuple) with two member fields that implements Comparable

For the map approach:

NavigableMap < String , SkillLevel > map = new TreeMap<>() ;
map.put( someLangString , someSkillLevel ) ;
map.put( someOtherLangString , someOtherSkillLevel ) ;
…

The key-value pairs will be automatically sorted by the natural order of the string keys.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM