Jak sprawdzić czy obiekt jest mutowalny albo niemutowalny?

0

Taki o to przykład:

Mam multimapę guavową.

Multimap<Long, String> mapa= HashMultimap.create();

Gdzieś w pętli dodaję sobie do mapy wpisy:

mapa.put(obiekt.getLiczba(), obiekt.getStringValue());

Co ciekawe (dla mnie) można dodać wpis z nullowym kluczem. I trochę psuje mi przez to "moją wizję", bo chciałem mieć nienullowe klucze lub wartości.

W takim razie decyduję się na napisanie metody filtrującej klucze:

    private void filterByNonNullKey(Multimap<Long, String> mapa) {
        Multimaps.filterKeys(mapa, new Predicate<Long>() {
            @Override
            public boolean apply(Long input) {
                return input != null;
            }
        });
    }

I teraz do pojawia się moje pytanie jak w temacie:

  1. Czy informacja (typ zwracany) na temat metody filterKeys mówi, że muszę jednak to przypisać do zmiennej i zwrócić?
  2. Czy jednak może być tak jak zrobiłem i ta pierwotna mapa z parametru metody filterByNonNullKey zostanie zmodyfikowana?
0

Bardzo rzadko w api masz metody które mutują parametr. W tym przypadku jest tak samo, co zresztą jasno wynika z dokumentacji.

Returns a multimap containing the mappings in unfiltered whose keys satisfy a predicate. The returned multimap is a live view of unfiltered; changes to one affect the other.
(...)
The returned multimap isn't threadsafe or serializable, even if unfiltered is.

Many of the filtered multimap's methods, such as size(), iterate across every key/value mapping in the underlying multimap and determine which satisfy the filter. When a live view is not needed, it may be faster to copy the filtered multimap and use the copy.

Sprawdziłeś w ogóle w dokumentacji? o_O

0

@Shalom Zmyliło mnie to: "The returned multimap is a live view of unfiltered; changes to one affect the other." I nie chodzi tu o to, że właśnie ten obiekt jest mutowalny? Może czegoś nie rozumiem. Albo mega kiepsko z angielskim u mnie :)

Bardzo rzadko w api masz metody które mutują parametr.

No dobrze, a co z przykładem np.:

public void usunObiektZListy(List lista){
//... tworzenie obiektu do usuniecia;
lista.remove(obiekt);
}

Lepszym rozwiązaniem byłoby tworzenie "kopii" i zwrócenie listy?

0

Słabo u ciebie z angielskim. Przytoczone zdanie oznacza że ta filtrowana mapa jest wrapperem na oryginalną mapę i zmiany w oryginalnej mapie będą widoczne także tutaj. To znaczy ze jeśli z oryginalnej mapy usuniesz jakiś element to z tej filtrowanej "też zniknie". Wyobraź sobie ze implementacja jest taka:

import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

class WrappedMap<T,S>{
    private final Map<T,S> originalMap;
    private final Predicate<T> predicate;

    WrappedMap(Map<T, S> originalMap, Predicate<T> predicate) {
        this.originalMap = originalMap;
        this.predicate = predicate;
    }

    Map<T,S> getElements(){
        return originalMap.entrySet().stream()
                .filter(x -> predicate.test(x.getKey()))
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue
                ));
    }
}

public class MapWrapper {
    public static void main(String[] args){
        Map<String,String> mapa = new HashMap<>();
        mapa.put("1", "a");
        mapa.put("11", "b");
        mapa.put("2", "c");
        WrappedMap<String, String> wrapped = new WrappedMap<>(mapa, key->key.startsWith("1"));
        for(Map.Entry<String, String> entry : wrapped.getElements().entrySet()){
            System.out.println(entry.getKey()+" "+entry.getValue());
        }
        mapa.remove("1");
        System.out.println("Po usunieciu:");
        for(Map.Entry<String, String> entry : wrapped.getElements().entrySet()){
            System.out.println(entry.getKey()+" "+entry.getValue());
        }
    }

}

Z tym usuwaniem to zależy do czego ci taka metoda potrzebna.

0

Jest gorzej @Shalom - mam problem z językiem polskim chyba, bo właśnie tak to zdanie przetłumaczyłem sobie.

I tak jak napisałem wyżej - skoro ta ostateczna mapa może się zmienić, jak zmienię te pierwszą to nie znaczy, że ta mapa jest właśnie mutowalna, modyfikowalna?

Czyli 1 mapa jest mutowalna i ta druga też bo zmienia się wtedy kiedy ta 1 się zmieni.

I w sumie nie odpowiedziano mi na główne pytanie. Co determinuje, że obiekt jest mutowalny lub nie. Mówisz, że rzadko są mutowalne parametry w metodach.
Czyli parametr zwracany determinuje to czy wrzucany obiekt był mutowalny czy nie? Bo tak jak masz w dokumentacji, którą przytoczyłeś:

Returns a multimap containing the mappings in unfiltered whose keys satisfy a predicate.

Mówi o tym, że zwraca multimapę, która spełnia jakiś tam warunek na podstawie tej niepofiltorwanej multimapy.

P. S Mam wrażenie, że mylę pojęcia w zależności od sytuacji/wykorzystania.

0

Co determinuje, że obiekt jest mutowalny lub nie

Kolekcje z zasady są mutowalne, poza bardzo szczególnymi implementacjami. Determinuje to dostępność metod pozwalajacych mutować pola. Jeśli masz metody typu set czy add to wiadomo że obiekt na którym pracujesz może sie zmienić. Podobnie jeśli masz metodę get która zwraca mutowalne pole. Obiekty niemutowalne to takie które na przykład mają tylko niemutowalne finalne pola.

Czyli parametr zwracany determinuje to czy wrzucany obiekt był mutowalny czy nie

Nie, ale może zasugerować czy metoda modyfikuje argument czy też nie. Niemniej poza szczególnymi przypadkami metoda nie modyfikuje przekazywanych parametrów.

0

@Shalom czyli nie da się tak łatwo tego określić prócz dokładnego sprawdzania w sumie po polach. Jeśli nie wszystkie są oznaczone final to jeszcze muszę sprawdzać metody.

Nie sądzisz, że takie filterKeys czy tak jak w Twoim przykładzie. Nie jest to niebezpieczne? Że masz mapę ABC. Potem tworzysz mapę pofiltrowaną XYZ. Ale jak zmienię coś w ABC to w tej drugiej mi się też zmieni to.

0

Nie, nie ma żadnej "prostej" metody żeby to sprawdzić. Technicznie rzecz biorąc pole nie musi być final o ile nie ma żadnej metody która przypisywałaby mu nową wartość ;)
Czemu niebezpieczne? To jest spodziewane zachowanie większości takich wrapperów w javie. Kopiowanie odbywa się tam niezwykle rzadko. Ale dlatego właśnie jest parcie na robienie obiektów niemutowalnych bo wtedy tego problemu nie ma bo masz pewność że "w międzyczasie" jakiś inny wątek ci nie zmieni obiektu na którym pracujesz.

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