Mam prostą metodę ustawiania właściwości i null
nie jest ona odpowiednia dla tej konkretnej właściwości. Zawsze byłem rozdarty w tej sytuacji: mam rzucać IllegalArgumentException
, albo NullPointerException
? Z javadocs oba wydają się odpowiednie. Czy istnieje jakiś zrozumiały standard? Czy to tylko jedna z tych rzeczy, które powinieneś robić, co wolisz, i obie są naprawdę poprawne?
547
IllegalArgumentException
jest w sprzeczności z obiektami Java.requireNonNull (T) i Guava's Preconditions.checkNotNull (T), który rzuca aNullPointerException
. Jednak właściwa odpowiedź jest zdecydowanieIllegalArgumentException
wyjaśniona w doskonałej odpowiedzi Jasona Cohena i jej sekcji komentarzy .Powinieneś używać
IllegalArgumentException
(IAE), a nieNullPointerException
(NPE) z następujących powodów:Po pierwsze, NPE JavaDoc wyraźnie wymienia przypadki, w których NPE jest odpowiedni. Zauważ, że wszystkie z nich są wyrzucane przez środowisko wykonawcze, gdy
null
są używane niewłaściwie. W przeciwieństwie do tego, JavaDoc IAE nie może być bardziej jasne: „Zgłoszony w celu wskazania, że metoda została przekazana nielegalny lub nieodpowiedni argument”. Tak, to ty!Po drugie, kiedy widzisz NPE w śladzie stosu, co zakładasz? Prawdopodobnie ktoś wyłuskał a
null
. Gdy widzisz IAE, zakładasz, że obiekt wywołujący metodę na górze stosu został przekazany w niedozwolonej wartości. Ponownie, to drugie założenie jest prawdziwe, pierwsze wprowadza w błąd.Po trzecie, ponieważ IAE jest wyraźnie zaprojektowane do sprawdzania poprawności parametrów, musisz założyć, że jest to domyślny wybór wyjątku, więc dlaczego miałbyś zamiast tego wybrać NPE? Z pewnością nie dla różnych zachowań - czy naprawdę spodziewasz się, że kod wywołujący będzie przechwytywał NPE oddzielnie od IAE i w rezultacie zrobi coś innego? Czy próbujesz przekazać bardziej szczegółowy komunikat o błędzie? Ale i tak możesz to zrobić w tekście komunikatu wyjątku, tak jak w przypadku wszystkich innych niepoprawnych parametrów.
Po czwarte, wszystkie inne niepoprawne dane parametrów będą IAE, więc dlaczego nie być spójne? Dlaczego nielegalne
null
jest tak wyjątkowe, że zasługuje na osobny wyjątek od wszystkich innych rodzajów nielegalnych argumentów?Wreszcie, akceptuję argument podany przez inne odpowiedzi, że części interfejsu API Java używają NPE w ten sposób. Jednak interfejs API języka Java jest niespójny ze wszystkim - od typów wyjątków po konwencje nazewnictwa, więc myślę, że po prostu ślepe kopiowanie (ulubiona część) interfejsu API języka Java nie jest wystarczającym argumentem, aby podważyć te inne względy.
źródło
Validate.notNull
(commons lang) iPreconditions.checkNotNull
(guava) rzucają NPE :-(checkArgument(arg != null)
, bez wygody zwracania arg, lub możesz utworzyć lokalne narzędzie do twojego projektu. ” code.google.com/p/guava-libraries/wiki/IdeaGraveyardStandardem jest rzucanie
NullPointerException
. Ogólnie nieomylna „Skuteczna Java” omawia to krótko w punkcie 42 (pierwsze wydanie), punkcie 60 (drugie wydanie) lub w punkcie 72 (trzecie wydanie) „Sprzyjanie stosowaniu standardowych wyjątków”:źródło
Byłem zwolennikiem rzucania
IllegalArgumentException
parametrów zerowych, aż do dzisiaj, kiedy zauważyłemjava.util.Objects.requireNonNull
metodę w Javie 7. Za pomocą tej metody, zamiast robić:możesz to zrobić:
i wyrzuci a,
NullPointerException
jeśli przekazany parametr tonull
.Biorąc pod uwagę, że ta metoda jest w samym środku,
java.util
uważam, że jej istnienie jest dość silnym wskaźnikiem, że rzucanieNullPointerException
jest „Java sposobem robienia rzeczy”.W każdym razie myślę, że tak.
Zauważ, że argumenty na temat twardego debugowania są fałszywe, ponieważ możesz oczywiście przekazać komunikat o
NullPointerException
tym, co było puste i dlaczego nie powinno być puste. Tak jak zIllegalArgumentException
.Jedną dodatkową zaletą
NullPointerException
jest to, że w kodzie o wysokiej wydajności można zrezygnować z jawnego sprawdzania wartości null (iNullPointerException
przyjaznego komunikatu o błędzie) i polegać tylko na tymNullPointerException
, że otrzymasz automatycznie, gdy wywołasz metodę na wartości null parametr. Pod warunkiem, że wywołasz metodę szybko (tj. Szybko się nie powiedzie), to masz zasadniczo ten sam efekt, ale nie tak przyjazny dla programisty. W większości przypadków lepiej jest to sprawdzić jawnie i rzucić użytecznym komunikatem wskazującym, który parametr ma wartość null, ale fajnie jest mieć opcję zmiany, jeśli wydajność decyduje bez zerwania opublikowanej umowy metody / konstruktora.źródło
Preconditions.checkNotNull(arg)
rzuca także NPE.Zwykle podążam za projektami bibliotek JDK, szczególnie kolekcji i współbieżności (Joshua Bloch, Doug Lea, ci faceci wiedzą, jak projektować solidne API). W każdym razie wiele interfejsów API w JDK aktywnie rzuca
NullPointerException
.Na przykład Javadoc dla
Map.containsKey
stanów:Wyrzucenie własnego NPE jest całkowicie poprawne. Konwencja polega na dołączeniu nazwy parametru, która była pusta w komunikacie wyjątku.
Wzór jest następujący:
Cokolwiek zrobisz, nie pozwól, aby ustawiono złą wartość, i rzuć wyjątek później, gdy inny kod spróbuje go użyć. To sprawia, że debugowanie to koszmar. Zawsze należy postępować zgodnie z zasadą „szybkiego działania”.
źródło
Zagłosował za argumentem Jasona Cohena, ponieważ został dobrze zaprezentowany. Pozwól mi rozebrać to krok po kroku. ;-)
NPE JavaDoc wyraźnie mówi, „inne nielegalne zastosowania obiektu null” . Gdyby ograniczono się tylko do sytuacji, w których środowisko wykonawcze napotyka zero, kiedy nie powinno, wszystkie takie przypadki można by zdefiniować o wiele bardziej zwięźle.
Nic na to nie poradzę, jeśli założysz coś niewłaściwego, ale zakładając, że enkapsulacja jest stosowana właściwie, naprawdę nie powinieneś się przejmować ani zauważać, czy wartość zerowa została dereferencyjnie nieodpowiednia w porównaniu z tym, czy metoda wykryła nieodpowiednią wartość zerową i zwolniła wyjątek.
Chciałbym wybrać NPE nad IAE dla wielu powodów
W rzeczywistości inne nieprawidłowe argumenty mogą powodować różnego rodzaju wyjątki. UnknownHostException , FileNotFoundException , różne wyjątki dotyczące błędów składniowych, wyjątek IndexOutOfBoundsException , błędy uwierzytelnienia itp. Itp.
Ogólnie uważam, że NPE jest bardzo złośliwe, ponieważ tradycyjnie jest związane z kodem, który nie przestrzega zasady szybkiego działania . To, a także fakt, że JDK nie wypełnił NPE ciągiem komunikatów, stworzył silny negatywny sentyment, który nie jest dobrze uzasadniony. Rzeczywiście, różnica między NPE i IAE z perspektywy środowiska uruchomieniowego jest ściśle nazwą. Z tego punktu widzenia, im bardziej precyzyjne jest imię, tym bardziej wyraźne jest połączenie z dzwoniącym.
źródło
To pytanie w stylu „Świętej Wojny”. Innymi słowy, obie alternatywy są dobre, ale ludzie będą mieli swoje preferencje, których będą bronić na śmierć.
źródło
NullPointerException
należy to rzucić: to konwencja używana przez JDK i wymagająca interfejsów, jest bardziej szczegółowa (tak jakIndexOutOfBoundsException
, itp.) Itp.Jeśli jest to
setter
metoda inull
jest do niej przekazywana, myślę, że sensowniej byłoby rzucićIllegalArgumentException
.NullPointerException
Wydaje się mieć więcej sensu w przypadku, gdy jesteś rzeczywiście próbuje użyćnull
.Tak więc, jeśli używasz go i to
null
,NullPointer
. Jeśli to były przekazywane i tonull
,IllegalArgument
.źródło
Apache Commons Lang ma wyjątek NullArgumentException, który robi wiele rzeczy omówionych tutaj: rozszerza IllegalArgumentException, a jego jedyny konstruktor przyjmuje nazwę argumentu, który powinien mieć wartość inną niż null.
Chociaż wydaje mi się, że rzucenie czegoś takiego jak NullArgumentException lub IllegalArgumentException dokładniej opisuje wyjątkowe okoliczności, ja i moi koledzy postanowiliśmy zastosować się do porady Blocha na ten temat.
źródło
Nie mogłem się bardziej zgodzić z tym, co zostało powiedziane. Niepowodzenie wcześnie, szybkie zawodzenie. Całkiem dobra mantra wyjątkowa.
Pytanie o to, który wyjątek rzucić, zależy głównie od osobistego gustu. Moim zdaniem IllegalArgumentException wydaje się bardziej konkretny niż używanie NPE, ponieważ mówi mi, że problem dotyczył argumentu przekazanego do metody, a nie wartości, która mogła zostać wygenerowana podczas wykonywania metody.
Moje 2 centy
źródło
W rzeczywistości kwestia wyrzucenia IllegalArgumentException lub NullPointerException jest moim skromnym zdaniem jedynie „świętą wojną” dla mniejszości z niepełnym zrozumieniem obsługi wyjątków w Javie. Ogólnie zasady są proste i wyglądają następująco:
Istnieją co najmniej trzy bardzo dobre powody, dla których nie należy mapować wszelkiego rodzaju naruszeń ograniczeń argumentów na IllegalArgumentException, przy czym trzeci prawdopodobnie jest tak poważny, że oznacza praktykę złym stylem:
(1) Programista nie może bezpiecznie założyć, że wszystkie przypadki naruszenia ograniczeń argumentów powodują IllegalArgumentException, ponieważ znaczna większość klas standardowych używa tego wyjątku raczej jako kosza na śmieci, jeśli nie ma dostępnego bardziej konkretnego rodzaju wyjątku. Próba odwzorowania wszystkich przypadków naruszenia ograniczeń argumentów na IllegalArgumentException w interfejsie API prowadzi tylko do frustracji programistów podczas korzystania z klas, ponieważ biblioteki standardowe przeważnie stosują różne reguły, które naruszają wasze, a większość użytkowników interfejsu API również ich używa!
(2) Odwzorowanie wyjątków prowadzi do różnego rodzaju anomalii spowodowanych pojedynczym dziedziczeniem: Wszystkie wyjątki Javy są klasami i dlatego obsługują tylko pojedyncze dziedziczenie. Dlatego nie ma sposobu na utworzenie wyjątku, który naprawdę mówi zarówno o NullPointerException, jak i IllegalArgumentException, ponieważ podklasy mogą dziedziczyć tylko z jednego lub drugiego. Zgłoszenie wyjątku IllegalArgumentException w przypadku argumentu zerowego utrudnia zatem użytkownikom API rozróżnienie problemów, ilekroć program próbuje programowo rozwiązać problem, na przykład poprzez podanie wartości domyślnych do powtórzenia wywołania!
(3) Mapowanie faktycznie stwarza niebezpieczeństwo maskowania błędów: Aby zamapować naruszenia ograniczeń argumentów na IllegalArgumentException, musisz zakodować zewnętrzny try-catch w każdej metodzie, która ma dowolne ograniczone argumenty. Jednak po prostu przechwytywanie wyjątku RuntimeException w tym bloku catch nie wchodzi w rachubę, ponieważ ryzykuje to mapowaniem udokumentowanych wyjątków RuntimeException zgłaszanych przez metody libery stosowane w twoim przypadku do IllegalArgumentException, nawet jeśli nie są one spowodowane przez naruszenie ograniczeń argumentów. Musisz więc być bardzo konkretny, ale nawet ten wysiłek nie chroni cię przed przypadkowym odwzorowaniem nieudokumentowanego wyjątku wykonawczego innego API (tj. Błędu) na IllegalArgumentException twojego API.
Z drugiej strony, przy standardowej praktyce, reguły pozostają proste, a wyjątek powoduje, że pozostają zdemaskowane i szczegółowe. W przypadku metody wywołującej zasady są również łatwe: - jeśli napotkasz udokumentowany wyjątek czasu wykonywania, ponieważ przekazałeś niedozwoloną wartość, powtórz wywołanie z wartością domyślną (w tym przypadku wyjątki są konieczne) lub popraw kod - jeśli z drugiej strony napotkasz wyjątek czasu wykonywania, który nie został udokumentowany dla danego zestawu argumentów, zgłoś błąd twórcom metody, aby upewnić się, że ich kod lub dokumentacja zostały naprawione.
źródło
Przyjęta praktyka polegająca na wykorzystaniu IllegalArgumentException (komunikat String) do zadeklarowania parametru jako niepoprawnego i podania jak największej liczby szczegółów ... Aby więc powiedzieć, że znaleziono parametr zerowy, a wyjątek inny niż null, zrobiłbyś coś lubię to:
Nie masz praktycznie żadnego powodu, aby pośrednio używać „NullPointerException”. Wyjątek NullPointerException to wyjątek zgłaszany przez wirtualną maszynę Java podczas próby wykonania kodu przy odwołaniu zerowym (jak toString () ).
źródło
Zgłoszenie wyjątku, który jest wyłączny dla
null
argumentów (niezależnie od tego,NullPointerException
czy jest to typ niestandardowy),null
zwiększa niezawodność automatycznego testowania. To zautomatyzowane testowanie można zrobić z refleksji i zbioru wartości domyślnych, jak w Guava s”NullPointerTester
. Na przykładNullPointerTester
próbowałby wywołać następującą metodę ...... z dwiema listami argumentów:
"", null
inull, ImmutableList.of()
. Sprawdziłby, że każde z tych połączeń generuje oczekiwaneNullPointerException
. Dla tej realizacji, przekazującnull
listy nie nie produkująNullPointerException
. Jednak zdarza się, że generuje,IllegalArgumentException
ponieważNullPointerTester
zdarza się, że używa domyślnego ciągu""
. JeśliNullPointerTester
oczekuje tylkoNullPointerException
nanull
wartości, to złapie bakcyla. Jeśli się spodziewaIllegalArgumentException
, tęskni.źródło
Niektóre kolekcje zakładają, że
null
jest odrzucane za pomocąNullPointerException
zamiastIllegalArgumentException
. Na przykład, jeśli porównasz zestaw zawierającynull
zestaw, który odrzucanull
, pierwszy zestaw wywołacontainsAll
drugi i złapie jegoNullPointerException
- ale nieIllegalArgumentException
. (Patrzę na wdrożenieAbstractSet.equals
.)Można zasadnie argumentować, że stosowanie w ten sposób niesprawdzonych wyjątków jest antypatternem, że porównywanie kolekcji zawierających
null
kolekcje, które nie mogą zawierać,null
jest prawdopodobnym błędem, który naprawdę powinien powodować wyjątek, lub żenull
w ogóle umieszczanie kolekcji jest złym pomysłem . Niemniej jednak, jeśli nie jesteś skłonny powiedzieć, żeequals
w takim przypadku należy wprowadzić wyjątek, utkniesz w pamięci, żeNullPointerException
jest to wymagane w pewnych okolicznościach, ale nie w innych. („IAE przed NPE, z wyjątkiem po„ c ”...”)źródło
new TreeSet<>().containsAll(Arrays.asList((Object) null));
wyrzuca,NPE
ponieważList
zawieranull
.Jako subiektywne pytanie należy to zamknąć, ale ponieważ nadal jest otwarte:
Jest to część polityki wewnętrznej stosowanej w moim poprzednim miejscu zatrudnienia i działała naprawdę dobrze. To wszystko z pamięci, więc nie pamiętam dokładnego sformułowania. Warto zauważyć, że nie korzystali ze sprawdzonych wyjątków, ale to wykracza poza zakres pytania. Niesprawdzone wyjątki, z których korzystali, dzieliły się na 3 główne kategorie.
NullPointerException: Nie rzucaj celowo. NPE mają być wyrzucane tylko przez maszynę wirtualną, gdy odwołuje się odwołanie zerowe. Należy dołożyć wszelkich starań, aby nigdy nie zostały wyrzucone. @Nullable i @NotNull powinny być używane w połączeniu z narzędziami do analizy kodu, aby znaleźć te błędy.
IllegalArgumentException: Zgłaszany, gdy argument funkcji nie jest zgodny z dokumentacją publiczną, dzięki czemu można zidentyfikować błąd i opisać go za pomocą przekazanych argumentów. Sytuacja PO mieści się w tej kategorii.
IllegalStateException: Zgłaszany, gdy funkcja jest wywoływana, a jej argumenty są albo nieoczekiwane w momencie ich przekazania, albo niezgodne ze stanem obiektu, do którego należy metoda.
Na przykład były dwie wewnętrzne wersje IndexOutOfBoundsException używane w rzeczach o długości. Jedna podklasa IllegalStateException, używana, jeśli indeks był większy niż długość. Druga podklasa IllegalArgumentException, używana, jeśli indeks był ujemny. Stało się tak, ponieważ można było dodać więcej elementów do obiektu, a argument byłby prawidłowy, a liczba ujemna nigdy nie jest poprawna.
Jak już powiedziałem, ten system działa naprawdę dobrze i trzeba było wyjaśnić, dlaczego istnieje takie rozróżnienie: „W zależności od rodzaju błędu łatwo jest wymyślić, co należy zrobić. Nawet jeśli tak naprawdę nie możesz dowiedzieć się, co poszło nie tak, możesz dowiedzieć się, gdzie można złapać ten błąd i utworzyć dodatkowe informacje debugowania ”.
NullPointerException: Obsługuj przypadek Null lub wstaw asercję, aby NPE nie został zgłoszony. Jeśli włożysz twierdzenie, to tylko jeden z dwóch pozostałych typów. Jeśli to możliwe, kontynuuj debugowanie tak, jakby to stwierdzenie było w pierwszej kolejności.
IllegalArgumentException: masz coś złego na stronie połączeń. Jeśli przekazywane wartości pochodzą z innej funkcji, dowiedz się, dlaczego otrzymujesz niepoprawną wartość. Jeśli przekazujesz jeden z argumentów propagujących, błąd sprawdza stos wywołań, aż znajdziesz funkcję, która nie zwraca oczekiwanej wartości.
IllegalStateException: Nie wywołałeś swoich funkcji w prawidłowej kolejności. Jeśli używasz jednego z argumentów, sprawdź je i wyślij IllegalArgumentException opisujący problem. Następnie możesz rozłożyć policzki na stosie, aż znajdziesz problem.
W każdym razie jego celem było to, że można kopiować tylko IllegalArgumentAssertions na stos. Nie ma możliwości propagowania wyjątków IllegalStateExceptions lub NullPointerExceptions na stosie, ponieważ miały one coś wspólnego z twoją funkcją.
źródło
Ogólnie rzecz biorąc, programista nigdy nie powinien zgłaszać wyjątku NullPointerException. Ten wyjątek jest zgłaszany przez środowisko wykonawcze, gdy kod próbuje wyrejestrować zmienną o wartości null. Dlatego jeśli twoja metoda chce jawnie zabronić wartości null, w przeciwieństwie do sytuacji, w której wartość null wywołuje wyjątek NullPointerException, powinieneś zgłosić wyjątek IllegalArgumentException.
źródło
Chciałem wyróżnić argumenty Null spośród innych nielegalnych argumentów, więc wyprowadziłem wyjątek z IAE o nazwie NullArgumentException. Nie muszę nawet czytać komunikatu wyjątku, wiem, że do metody przekazano argument zerowy, a czytając komunikat, dowiaduję się, który argument był pusty. Nadal wychwytuję wyjątek NullArgumentException za pomocą procedury obsługi IAE, ale w moich logach szybko widzę różnicę.
źródło
dychotomia ... Czy się nie pokrywają? Tylko dublotomia mogą się nakładać tylko na nie nakładające się części całości. Jak to widze:
źródło
NullPointerException
nic nie zrobiłoby. Jedyną rzeczą, która może pomóc, jest toIllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException
, że nie mamy wielokrotnego dziedziczenia.NullPointerException
wyrzucane podczas próby uzyskania dostępu do obiektu za pomocą zmiennej referencyjnej, której bieżącą wartością jestnull
.IllegalArgumentException
wyrzucany, gdy metoda odbiera argument sformatowany inaczej niż oczekuje metoda.źródło
Według twojego scenariusza
IllegalArgumentException
jest najlepszym wyborem, ponieważnull
nie jest prawidłową wartością dla Twojej nieruchomości.źródło
W idealnym przypadku wyjątki czasu wykonywania nie powinny być zgłaszane. Dla Twojego scenariusza należy utworzyć sprawdzony wyjątek (wyjątek biznesowy). Ponieważ jeśli którykolwiek z tych wyjątków zostanie zgłoszony i zarejestrowany, wprowadzi w błąd programistę podczas przeglądania dzienników. Zamiast tego wyjątki biznesowe nie powodują tej paniki i zwykle są ignorowane podczas rozwiązywania problemów z dziennikami.
źródło
Definicje z łączy do dwóch powyższych wyjątków to IllegalArgumentException: Zgłoszony w celu wskazania, że do metody przekazano niedozwolony lub nieodpowiedni argument. NullPointerException: Zgłaszany, gdy aplikacja próbuje użyć wartości null w przypadku, gdy wymagany jest obiekt.
Dużą różnicą tutaj jest to, że IllegalArgumentException powinien być używany podczas sprawdzania poprawności argumentu dla metody. NullPointerException ma być używany za każdym razem, gdy obiekt jest „używany”, gdy jest pusty.
Mam nadzieję, że to pomoże spojrzeć na te dwa z perspektywy.
źródło
Jeśli jest to „ustawiający” lub gdzieś, z którego członka mogę skorzystać później, zwykle używam IllegalArgumentException.
Jeśli jest to coś, czego zamierzam teraz użyć (dereferencję) w tej metodzie, proaktywnie rzucam wyjątek NullPointerException. Podoba mi się to lepiej niż pozwalanie na to środowisku wykonawczemu, ponieważ mogę dostarczyć pomocnej wiadomości (wygląda na to, że środowisko wykonawcze też może to zrobić, ale to rant na kolejny dzień).
Jeśli przesłaniam metodę, używam tego, czego używa przesłonięta metoda.
źródło
Powinieneś zgłosić IllegalArgumentException, ponieważ sprawi to, że programiści zrozumieją, że zrobił coś nieprawidłowego. Programiści są tak przyzwyczajeni do wyświetlania NPE przez maszynę wirtualną, że żaden programista nie od razu zda sobie sprawę z jego błędu i zacznie rozglądać się losowo lub, co gorsza, obwinia kod za buggy.
źródło
W takim przypadku IllegalArgumentException przekazuje użytkownikowi za pomocą interfejsu API jasne informacje, że „nie powinno być zerowe”. Jak zauważyli inni użytkownicy forum, możesz użyć NPE, jeśli chcesz, o ile przekażesz odpowiednie informacje użytkownikowi za pomocą interfejsu API.
GaryF i tweakt porzucili referencje „Effective Java” (które przysięgam), które zalecają używanie NPE. A sprawdzenie, jak zbudowane są inne dobre interfejsy API, jest najlepszym sposobem, aby zobaczyć, jak zbudować interfejs API.
Innym dobrym przykładem jest spojrzenie na Spring API. Na przykład org.springframework.beans.BeanUtils.instantiateClass (Constructor ctor, Object [] args) ma linię Assert.notNull (ctor, „Constructor nie może mieć wartości null”). org.springframework.util.Assert.notNull (Object object, String message) metoda sprawdza, czy przekazany argument (obiekt) ma wartość NULL, a jeśli tak, zgłasza nowy wyjątek IllegalArgumentException (wiadomość), który jest następnie przechwytywany w org. metoda springframework.beans.BeanUtils.instantiateClass (...).
źródło
Jeśli zdecydujesz się wyrzucić NPE i użyjesz argumentu w swojej metodzie, jawne sprawdzenie wartości null może być zbędne i kosztowne. Myślę, że VM już to dla ciebie robi.
źródło
NPE
a programiści zabiorą głosIAE
przed VM, jeśli chcą.