Testy z Javy – oblíbený příklad

Nemám rád takové ty testové otázky, které se skládají z výpisu kódu přibližně o dvaceti řádcích následovaného otázkou, co program po spuštění vypíše na konzoli, s možnostmi odpovědí, z nichž ty první v pořadí jsou kompilační chyba, chyba za běhu a nic se nestane. O respondentovi se dozvíte nejspíše jenom to, jak si dokáže všímat detailů. Což se může hodit, ale není to všechno. Navíc například mě osobně takové testy urážejí, protože si s nimi někdo nedal žádnou práci, prostě je opsal z příkladů k certifikaci, a opravování si chce také maximálně ulehčit.

Já mám raději příklady, ze kterých jsem schopen odhadnout, kolik toho má ten člověk za sebou. Jeden z mých oblíbených spočívá v tom, že chci implementovat následující metodu:


/**

* Removes from collection all items that contain given text.

* Supposes  parameters are not null and  the collection doesn't contain null.

*/

public void filter(Collection<String> collection, String text) {

// TODO: implement

}

Když se ti, kteří neumějí procházet kolekce, odebéřou zjišťovat, jak udělají z kolekce pole, které si pak proběhnou přes indexy, dostaneme první skupinu, která napíše toto:


for (String item : collection) {

  if (item.contains(text)) {

    collection.remove(item);

  }

}

Což skončí výjimkou ConcurrentModificationException. Autor kódu tedy něco o Javě ví, ale moc toho nenaprogramoval. Zkušenější, ale stále ještě junior, si zkusí poradit nějak takto:


Collection<String> toBeRemoved = new ArrayList<>();

for (String item : collection) {

  if (item.contains(text)) {

    toBeRemoved .add(item);

  }

}

collection.removeAll(toBeRemoved);

Což už výjimky generovat nebude. Autor má něco za sebou, ale spokojí se s prvním řešením, které ho napadlo nebo ho někde opsal. Kód, který chci vidět, vypadá takto:


for (Iterator<String> iterator = collection.iterator(); iterator.hasNext();) {

  String item = iterator.next();

  if (item.contains(text)) {

    iterator.remove();

  }

}

A je to. Iterátor umí použít kdekdo. Ale dost lidí zná dvě metody toho rozhraní. Tu třetí ignoruje.

Edit: Obdržel jsem rozumnou připomínku, že mé nejlepší řešení nemusí fungovat pro všechny typy kolekcí, ano, z metody může vyletět UnsupportedOperationException. Ale myslím si, že se dá považovat za zodpovědnost volajícího, že chce modifikovat kolekci, která modifikaci umožní.

komentáře 4

  1. Kolego, pakliže jste si nadefinoval zadání „Removes from collection all items that don’t contain given text.“, neměla by podmínka ve Vašich příkladech být „if (!item.contains(text))“ ?

  2. Měl bych takovou připomínku k designu/konvenci. Vím že tady bude mít přednost zadání (nebo Javadoc), ale čekal bych, že metoda filter vrátí novou vyfiltrovanou kolekci. Protože kdybych filtroval z více míst, tak nevím (a neuhlídím) co se mi s tou kolekcí děje. Navíc nemůžu filtrovat dvakrát po sobě (resp. jednotlivé filtry budou v konjunkci).

    1. To je asi relevantní připomínka. Mně se na tomhle líbí, že je to pro volajícího jasně čitelné. Ta metoda nic nevrací, tudíž evidentně modifikuje vstup. Když vidím metodu, která kolekci přebírá a vrací, přiznám se, že pak jdu do zdrojového kódu sondovat, zda se mi v té kolekci hrabe nebo ne. A jsem v pokušení předávat jí unmodifiable proxynu namísto mé kolekce. Jestliže pak jako uživatel void verze metody chci zabránit modifikacím, předám kopii. Tím mám mimo jiné třeby i zajištěno, že se mi nebudou vytvářet a zahazovat kopie kolekcí obřích rozměrů, když to nepotřebuji.

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *