Sytuacja kobiet w IT w 2024 roku
14.10.20214 min
Miloš Živković

Miloš ŽivkovićSoftware Engineerenjoy.ing

5 okropnych snippetów Javy i ich alternatywy

Spooktober is comming, czyli jak rozpracowałem 5 "strasznych" snippetów Javy.

5 okropnych snippetów Javy i ich alternatywy

Czy używasz random? Czy pracujesz z wyjątkami? Czy wyszukujesz wartości null?
Jeśli odpowiedziałeś twierdząco, powinieneś poznać te okropne snippety. Zobacz, jak daleko sięga głupota ludzka. Oto 5 okropnych snippetów Javy i ich lepsze alternatywy.

1. Czy generujesz losowe liczby?

Im dłużej patrzysz, tym gorzej to wygląda. Jest to zakres owinięty nieskończoną pętlą. Kod zapętla się do momentu wygenerowania poprawnej liczby.


W jaki sposób generowany jest zakres? Zakres może wynosić 100 lub 1_000_000, a nawet więcej. Nie będzie on istniał dla ujemnego CODE_LENGTH. Nieskończona pętla mogłaby działać w nieskończoność i zatrzymać wykonywanie procesu.

final double base = 10.0;
final int minCode = (int)Math.pow(base, CODE_LENGTH - 1) - 1;
final int maxCode = (int)Math.pow(base, CODE_LENGTH) - 1;

while (true)
{
    final int code = codeGenerator.nextInt();
    if ((code > minCode) && (code <= maxCode))
    {
        return String.valueOf(code);
    }
}


Zamiast tego można użyć java.util.Random#nextInt(bound). Określasz górną granicę, która nie włącza się do generowany liczb. Dodajesz liczbę minimalną i otrzymujesz pożądaną liczbę losową.

public int getRandomNumberUsingNextInt(int min, int max) {
    Random random = new Random();
    return random.nextInt(max - min) + min;
}

2. Czy wiesz, jak działa float?

Jak powiedział kiedyś pewien OP: "Chciałem 2,25, ale zamiast tego dostałem 1,2500001" Brak wiedzy na temat standardów IEEE wraca ze zdwojoną siłą!

Float f = 1.25f;
int i = Float.floatToIntBits(f);
i++;
f = Float.intBitsToFloat(i);


Jeśli chciałeś 2,25, dodaj 1. Nie ma potrzeby konwertowania. Java wie, czego chcesz.

Czy chcesz dodać 1 do jednostki najmniejszej precyzji? Użyj tego:
current + Math.ulp(current);

Możesz również użyć Math#nextUp. nextUp zajmie się przypadkami brzegowymi za Ciebie.

Zapoznaj się ze standardami IEEE, które opisują jak przechowujemy floaty. Wiedza ta pozwala na wyeliminowanie podstawowych błędów popełnianych przez nowicjusza

3. Czy wiesz, co to jest herezja wyjątku?

"To jakaś herezja!" - mówi jeden z moich seniorów przyglądający się najgorszym praktykom. I słusznie, bo nazywanie tego złą praktyką nie jest poprawne.

"Wyjątek sam się obsługuje"
Nigdy byś o tym nie pomyślał, a jednak istnieje taki kod.

class MyException extends Exception {
	public void handle() { /* handler with 9000 lines */ }
}

class MyClass {
	public void myMethod() {
		try { /* ... */ }
		catch (MyException e) {
			e.handle();
		}
	}
}


Będę kontynuował z innymi heretycznymi przykładami. Następujące kompilują się i pozostawię je bez komentarza.

public void thr0w() throws MyException
{
    throw this;
}
public MyException() throws MyException
class Uncatchable extends Throwable {

    public Uncatchable() {
        throw this;
    }
}

4. Jak uzyskać pierwszą wartość inną niż null?

Istnieje kilka sposobów na znalezienie pierwszej wartości innej niż null. Oto jak nie należy tego robić.

public static String elvis(String value, String ifNull) {
    return value == null ? ifNull : value;
}

public static Boolean elvis(Boolean value, Boolean ifNull) {
    return value == null ? ifNull : value;
}

public static Object elvis(Object value, Object ifNull) {
    return value == null ? ifNull : value;
}


Jeśli potrzebujesz sprawdzić tylko dwie wartości, użyj Optional#ofNullable. Gdy pierwsza wartość to wartość null, użyj orElse, aby zwrócić drugą. Możesz także połączyć Optional#ofNullable z niestandardowym orElseGet i dostarczyć Supplier.

Jak odnaleźć pierwszą wartość inną niż null ze zbioru? Nie rób tego w ten sposób. Nie ma potrzeby wprowadzania Object, kiedy masz typy generyczne.

Object coalesce(Object... objects)
{
    for(Object o : object)
        if(o != null)
            return o;
    return null;
}


Jeżeli połączysz strumienie, wartościowanie leniwe i typy generyczne, to pozbędziesz się konwersji. Otrzymalibyśmy następujące rozwiązanie.

public static <T> T coalesce(T... t) {
    return Stream.of(t).filter(Objects::nonNull).findFirst().orElse(null);
}

Możesz również użyć firstNonNull z biblioteki Apache Commons.

5. Jak tworzysz katalogi?

Ku mojemu zaskoczeniu, była to metoda z Javy 7. Proste, łatwe do zrozumienia i trudne do debugowania.

public boolean mkdir()


Zwraca: true wtedy i tylko wtedy, gdy katalog został utworzony; w przeciwnym wypadku false.

Tak więc false reprezentuje nieobecny katalog nadrzędny, brak uprawnień i inne wyjątki wejścia/wyjścia. A jakie są inne wyjątki wejścia/wyjścia? Tutaj znajduje się pełna lista:

  • Katalog nadrzędny dla katalogu może nie istnieć

  • Własność i uprawnienia katalogu nadrzędnego mogą być nieprawidłowe

  • Aplikacja może nie mieć pozwolenia na zapis w tym systemie plików.

  • Urządzenie może służyć tylko do odczytu

  • Urządzenie może być uszkodzone lub z błędami sprzętowymi

  • System plików może być tak zapełniony, że nie można utworzyć katalogu.


false nic nie mówi, a ta metoda nie powinna być używana

Dzisiaj mamy już metodę Javy 8. Ta metoda wyrzuca różne IOExceptions, zwraca the Path i akceptuje atrybuty plików.

public static Path createDirectory(Path dir,
                                   FileAttribute<?>... attrs)
                            throws IOException

Bonus: Czy używasz Javadocs?

Znowu zostawię to w sekcji bez komentarza - Zamierzona gra słów.

/**
 * 
 * 
 * @param wb
 * @param sheet
 * @param row
 * @param borderDashedRight
 * @param borderDashedLeft
 * @param borderDashedRightLeft
 * @param fulBorderCalignFont10
 * @param forSummary
 */
private void mergeCellsForRows(HSSFWorkbook wb, HSSFSheet sheet,
		HSSFRow row, HSSFCellStyle borderDashedRight,
		HSSFCellStyle borderDashedLeft,
		HSSFCellStyle borderDashedRightLeft,
		HSSFCellStyle fulBorderCalignFont10, boolean forSummary)


Nauka o tym, jak działa float, może już nie być tak pomocna. Mimo to, znajomość różnic jest korzystna dla programisty — np. znajomość różnicy między float i double oraz ich reprezentacja w pamięci.

Wartości losowe mają swoje przypadki użycia. Zawsze ostrożnie podchodź do kwestii generowania liczb losowych. Pamiętaj jednak, że system generacji wartości losowych wbudowany w Javę rozwiąże większość Twoich problemów

Dowiedz się więcej o typach generycznych i używaj ich zamiast Object. Więcej dowiesz się z tej książki: "Java Generics and Collections".

Nie używaj typów logicznych do przedstawiania błędów. Są one binarne i nie przedstawiają ich wiele. Aby pokazać błędy, użyj wyjątków.

Wpadnij po mojego e-booka.

Napisałem już wiele złych snippetów w Javie. Znajdziesz je na moim Gumroad. Złotówka czy dwie wsparcia pomogą mi stworzyć lepszego e-booka i wypuścić go za darmo :)



Oryginał tekstu w języku angielskim przeczytasz tutaj.

<p>Loading...</p>