2015-06-19 14 views
8

sprawdzamy jakość naszego kodu przy użyciu sonaru i Sonar znaleźć kod, który porównuje obiekty tożsamości tak:Kontrola obiektów dla tożsamości i Sonar wystawia

if (cellOfInterest == currentCell) { … } 

Sonar znajdzie tego rodzaju kontroli tożsamości osobliwego wystarczy nazwać to krytycznym i proponuje zastąpienie sprawdzania tożsamości (przy użyciu ==) sprawdzeniem równości (używając zamiast tego .equals()). Kontrole tożsamości, więc uzasadnienie tego jest często nie to, co rozumie się.

W naszym przypadku jednak mamy iterację listy Cell s i sprawdzić w każdej iteracji (currentCell) czy jesteśmy obsługi specjalną komórkę już mamy (cellOfInterest).

Chciałbym usłyszeć, czy są inne wzory niż nasze, które są powszechne i które unikają tego problemu po prostu przy użyciu innego projektu. Albo jakie rozwiązania proponujesz, aby uniknąć korzystania z kontroli tożsamości we wspomnianej sytuacji?

Zastanawialiśmy się nad zastąpieniem sprawdzania tożsamości za pomocą kontroli równości, jak opisano powyżej, ale nie wydaje się mieć zastosowania w naszej sytuacji, ponieważ inne komórki mogą być "równe", ale nie identyczne.

Wszystkie pomysły są mile widziane!

+0

Dlaczego spadamy? Prosimy o komentarz w takich przypadkach! Nie mam pojęcia, jak poprawić moje pytanie, jeśli nie powiesz mi, co cię popchnęło. – Alfe

+0

Czy wszystkie te komórki należą do określonej klasy? –

+0

Powiedzmy "tak", podzielmy także pytanie na dwie części, gdy powiemy, że klasa pochodzi z biblioteki innej firmy, więc nie można jej dotknąć; i kiedy mówimy, że to nasza własna klasa i można ją zmienić. – Alfe

Odpowiedz

2

W przypadku ciągów i większości innych obiektów Java możliwe jest posiadanie 2 wystąpień o nierównej tożsamości, ale w rzeczywistości są one równoważne przez .equals. Konwencjonalne jest unikanie porównania z wartością == (zamiast tego za pomocą equals lub compareTo), ale jeśli działa, działa. Możesz oznaczyć przedmiot jako fałszywy alarm w SonarQube.

+0

Hm, nie, nie zgodziłbym się z podejściem, że działa to oznacza, że ​​jest fałszywie pozytywny. Kod może działać doskonale i mimo wszystko być wadliwy. Wady niektórych implementacji pojawiają się tylko wtedy, gdy kod jest zachowywany lub rozszerzany. – Alfe

1

Na początku nie napotkasz problemów, jeśli zastąpisz sprawdzanie tożsamości za pomocą równego połączenia (z tą różnicą, że będziesz musiał sprawdzić wartości puste w cellOfInterest), ponieważ domyślną implementacją równości w obiekcie jest sprawdzanie tożsamości .

if (cellOfInterest != null && cellOfInterest.equals(currentCell)) { … } 

nie złamie kodu. Zachowuje się dokładnie tak samo jak twój kod, kiedy mogę przypuszczać, że currentCell nie będzie miało wartości NULL.

Aby pominąć sprawdzanie zerowej (pomyłki i zachowanie obu wartościach będących null) można również używać (ponieważ Java 7)

if(Objects.equals(cellOfInterest, currentCell)) { ...} 

Ogólnie korzystających równymi jest lepsza architektura.

Aby zobaczyć obu przypadkach wymienionych:

  • Jeśli klasa jest zmienna od siebie, może (lub nie może) doszli do wniosku, że istnieją lepsze sposoby niż równości tożsamości; więc po prostu zmień równe (i nie zapomnij o hashCode!) w klasie.

  • Jeśli nie możesz zmienić klasy, musisz zaufać znaczącej implementacji równości i hashCode przez dostawcę klasy.

+0

Dla tych instancji 'Cell 'zakładałbym, że dwie puste komórki, które nie są identyczne, nadal będą uznawane za równe, więc wszelkie' .equals () 'specjalne dla tych' Cell's powinno to zaimplementować. W tym przypadku użycie '.equals()' złamałoby nasz kod. – Alfe

+0

Nie, będą równe, ponieważ każdy obiekt w Javie rozszerza obiekt, który implementuje go za pomocą tożsamości. –

+0

Części twojej odpowiedzi brzmią, jakbym był zainteresowany porównaniem dwóch obiektów za bycie * podobnym * (to znaczy, że "równa się()" oznacza). Ale jestem * tylko * zainteresowany sprawdzaniem tożsamości. Nic innego nie rozwiąże mojego problemu (chyba, że ​​jest to zupełnie inne podejście, które całkowicie unika porównań). Szukam tylko sposobów * wyrażenia * tej kontroli tożsamości w taki sposób, aby Sonar ją zaakceptował, prawdopodobnie dlatego, że jest ona bardziej wyraźna niż prosty operator '=='. – Alfe

7

Jeśli tożsamość jest tym, czego potrzebujesz, to jest to, czego potrzebujesz. Ostrzeżenie ma sens, ponieważ często jest błędem, ale w tym przypadku nie jest.

Jako przykład IdentityHashMap (która współpracuje z tożsamością vs. równości) ma to w swojej javadoc:

Ta klasa nie jest realizacja Mapa ogólnego przeznaczenia! [...] Ta klasa jest przeznaczona do użycia tylko w rzadkich przypadkach, w których wymagana jest semantyka równania odniesienia.

Jest więc rzadko przydatny, ale ma swoje zastosowania. Jesteś na podobnej pozycji. I oczywiście, its internal code robi dokładnie to, czego się spodziewasz, używa ==, aby zdobyć klucz. Konkluzja: Nie widzę powodu, dla którego kod musiałby być bardziej złożony, ponieważ niektóre narzędzie do analizy statycznej kodu mówi, że może to być problem - takie narzędzie ma ci pomóc, a nie zmuszać do jakiś dziwny konstrukt, który w zasadzie zrobi to samo. Wyjaśnię, dlaczego == jest używany w komentarzu dla jasności, oznacz go jako fałszywy alarm i przejdź dalej.

Jeśli naprawdę chcesz, aby usunąć ostrzeżenie, jedyną opcją mogę myśleć jest użycie equals i zmienić metodę equals albo:

  • domyślny Object#equals która opiera się na tożsamości
  • niektóre implementacja, która jednoznacznie identyfikuje komórki, być może na podstawie jakiegoś unikalnego identyfikatora lub współrzędnych?
+0

Czy istnieje sposób wywołania metody 'Object.equals()' dla dwóch wystąpień? Czy mogę pobrać adres instancji, aby to porównać? (To sprawnie sprawdzi sprawdzenie tożsamości i prawdopodobnie będzie wystarczająco wyraźne, aby Sonar nie mógł narzekać). – Alfe

+1

@Alfe (1) Musisz usunąć metodę "równości" z klasy Komórka, aby odziedziczyć domyślne zachowanie - jeśli potrzebujesz "równa się" metoda dla innych celów, więc nie sądzę, że istnieje sposób. (2) Można użyć 'System.identityHashCode', ale możliwe są kolizje - więc nie jest to opcja. W końcu język ma określonego operatora dla twojego celu, to jest '==', a każde obejście będzie polegało na ukryciu użycia '==' do Sonaru, ale użyje go gdzieś ... Na przykład możesz dodać '. static isIdentical (Celi c1, Celi c2) {return c1 == c2; } 'ale sonar prawdopodobnie też na to narzeka ... – assylias