Параллельная карта с одним ключом и несколькими значениями - PullRequest
1 голос
/ 27 марта 2020

Мне нужна карта, которая является поточно-ориентированной и может иметь несколько значений. Я написал один, используя MultiMap как

    private MultiMap<String, String> uploadIdETagMap = new MultiValueMap<String, String>();

//Function to get tag value and add to map to that uploadId key
    public void uploadPartForMultiPartUpload() {
        try {
            UploadPartRequest partRequest = new UploadPartRequest();
            partRequest = partRequest.withBucketName(bucketName).withInputStream(inputStream).withKey(fileName)
                    .withPartNumber(partNumber).withUploadId(uploadId).withPartSize(sizeOfData)
                    .withLastPart(isLastPart);
            UploadPartResult result = s3Client.uploadPart(partRequest);
            uploadIdETagMap.put(uploadId, result.getPartETag());
        } catch (Exception e) {
            log.error("Error uploading part: {} in multi part upload.", partNumber, e);
        }
    }

    List<String> tagList = (List<String>) uploadIdETagMap.get(uploadId);

Так что каждый раз, когда я получу новое значение тега для определенного ключа uplaodId, мне понадобятся все эти теги в конце, и одновременно будут обрабатываться другие загрузки .

В приведенном выше коде tag добавляется каждый раз в качестве значения MultiMap для указанного ключа c uploadId. Приведенный выше код работает, но и MultiMap, и MultiValueMap устарели и не являются поточно-ориентированными.

Так что любые предложения, как я могу добиться этого с помощью последней версии и безопасности потоков.

Ответы [ 2 ]

3 голосов
/ 27 марта 2020

tl; др

personFavoriteColors.computeIfAbsent( 
    "Alice" , 
    ( x -> new CopyOnWriteArrayList<>() )
)
.add( "Purple" )
;

personFavoriteColors.computeIfAbsent( 
    "Alice" , 
    ( x -> new CopyOnWriteArrayList<>() )
)
.add( "Gold" )
;

personFavoriteColors.toString (): [Фиолетовый, Золотой]

Map::computeIfAbsent

Java теперь имеет поведение multimap , встроенное в новый метод computeIfAbsent, определенный в интерфейсе Map.

Определите вашу карту.

ConcurrentMap< String , Set< String> > personFavoriteColors = new ConcurrentSkipListMap<>() ;

Мы используем реализацию Map, которая реализует интерфейс ConcurrentMap для обеспечения безопасности потоков, как вы и просили. Java предлагает две такие реализации.

Table of map implementations in Java 11, comparing their features

Используйте одну строку для создания нового списка или набора для хранения нескольких значений.

personFavoriteColors.computeIfAbsent( 
    "Alice" , 
    ( x -> new CopyOnWriteArraySet<>() )   // Lambda expression. Run only if needed to run (if absent). 
)                                          // Returns the value of a map (a `Set` or `List` when desiring a multimap). 
.add( "Purple" )
;

Вы можете получить доступ к Set (или List) за пределами Map, которому он принадлежит. Так что Set (или List) также должны быть параллельными.

Здесь мы использовали параллельный набор, CopyOnWriteArraySet в качестве значения карты.

Например:

Set< String > favoriteColorsForAlice = personFavoriteColors.get( "Alice" ) ;
System.out.println( favoriteColorsForAlice ) ; 

Смотрите это код работает на IdeOne.com .

[фиолетовый, золотой]

2 голосов
/ 27 марта 2020

Для какой бы реализации Map<String,List<String>> вы ни использовали, вы можете сделать следующее:

String key;
String value;
map.compute(key, ((k,v)-> v == null ? new ArrayList<>() : v).add(value));

Выше проверяет, существует ли ключ List<String> for, если он не создан, в противном случае он использует существующий. В обоих случаях значение добавляется в новый или существующий список для данного ключа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...