Dlaczego projektanci Java nie stworzyli statycznych wersji metod manipulacji ciągami w java.lang.String
klasie? Odnoszę się do następujących metod, ale pytanie można rozszerzyć również na inne metody niestatyczne w klasie.
concat(String) substring(int, int)
replace(char, char) toLowerCase()
replace(CharSequence, CharSequence) toLowerCase(Locale)
replaceAll(String, String) toString()
replaceFirst(String, String) toUpperCase()
split(String) toUpperCase(Locale)
split(String, int) trim()
substring(int)
Posiadanie tylko niestatycznych wersji tych metod wymusza jawne sprawdzanie wartości NULL wszędzie tam, gdzie taka metoda musi zostać wywołana. Na przykład zwykłe wywołanie example = example.trim()
prowadziłoby do NullPointerException if String example = null
. Dlatego programista musi wykonać następujące sprawdzenie wartości zerowej płyty kotłowej:
if (example != null)
example = example.trim();
// OR:
example = (example==null) ? null : example.trim();
example = (example==null) ? null : example.substring(5);
Wyobrażam sobie, że znacznie wygodniej byłoby String
mieć statyczne wersje tych metod (być może nawet wyłącznie ), które przyjmowałyby ciąg wejściowy jako pierwszy argument:
example = String.trim(example);
example = String.replace(example, 'a', 'b');
example = String.substring(example, 5);
Doprowadziłoby to do czystszego kodu napisanego przez programistów, który automatycznie zajmowałby się zerowymi przypadkami, po prostu zwracając null, zamiast zmuszania programistów do jawnej obsługi przypadków zerowych. Powrocie null sens dla mnie, ponieważ manipulowanie zerowy ciąg powinno skutkować pustym ciągiem, a nie błędów.
Dlaczego projektanci Java o tym nie pomyśleli, projektując String
klasę w Javie 1 lub Java 2, ani nawet nie dodając takiej funkcjonalności w późniejszej wersji Java?
źródło
null
jest stanem wyjątkowym i należy go traktować wyraźnie.Maybe<T>
Chyba słaba reimplementacja tego typu?string name = employee?.personalData?.name
. Tak jak skrót do wszystkich tych powtarzających sięif (employee != null)
s. Powiązane SO pytanie: stackoverflow.com/questions/1196031/...Odpowiedzi:
To jest twoja opinia. Inni mogą argumentować, że operacje na łańcuchach znaków na pustym obiekcie, który nie zawiera łańcucha, nie mają sensu i dlatego powinny zgłaszać wyjątek
Dlaczego „projektanci Java” zrobili lub nie zrobili czegoś, trudno jest odpowiedzieć.
Istnieją już biblioteki, które mogą wykonywać zerowe operacje na łańcuchach, np. StringUtils z Apache Commons. Możesz użyć tej lub podobnych bibliotek, jeśli ich potrzebujesz.
Dodanie na podstawie twoich komentarzy
Czytając komentarze, wydaje się, że prawdziwym problemem jest to, że musisz sprawdzić
null
cały kod. Może to wskazywać na zły projekt programu bez jasno określonych umów między interfejsami. Możesz przeczytać Unikanie instrukcji „! = Null” w Javie?źródło
Optional
- code.google.com/p/guava-libraries/wiki/…IMO całe podejście „jeśli argument jest zerowy zwraca null” niepotrzebnie zwiększa cykliczną złożoność twojego programu.
Wczesne biblioteki Java korzystały z metody return null, ale chłopaki JDK zawsze chronili się przed wartością null z wyjątkami.
Z czasem myślę, że to drugie podejście okazało się wyraźnym zwycięzcą.
Dlaczego? Ponieważ pola zerowe łamią wiele zasad oo. Po prostu nie można ich traktować jako członków klasy polimorficznej. Oznacza to, że zawsze musisz zakodować specjalne przypadki dla wartości zerowej, a zatem twoja cykliczność rośnie, gdy musisz założyć, że wszystko może być zerowe.
Aby rozwiązać problemy, rozważ użycie wzorca obiektu zerowego zamiast polegania na polach zerowych.
źródło
String
czy nie jest polimorficzny, nie? W jaki sposób używasz wzorca obiektu zerowego dla już istniejącego typu, takiego jak String?int
ma wartość zeronull
. Pod względem koncepcyjnym powinna istnieć możliwość posiadaniastring
typu, którego domyślną wartością byłby pusty ciąg, a nienull
[taki typ mógłby semantycznie odpowiadać temu,String
coint
jestInteger
]. Fakt, że niepustestring
wewnętrznie zawierałoby odwołanie do obiektu sterty, byłby szczegółem implementacji; nie ma powodu, dla którego nie mógłby zachowywać się semantycznie jak prymityw.Nie mówię, że to jest powód, ale oprócz toString, wszystkie te metody można łatwo zamknąć w statycznej klasie pomocniczej, podczas gdy odwrotna sytuacja nie jest prawdą.
To znaczy, jeśli chcesz Stings.toUpper (ciąg wejściowy), kod jest łatwy do napisania, ale jeśli chcesz instance.toUpper i wszystko, co masz, to String.toUpper, cóż, to niemożliwe ... chyba że wprowadzą metody rozszerzenia, co najprawdopodobniej nawet wtedy nie było brane pod uwagę.
źródło
String.format
(statyczny), ale nie możesz"something %s".format(id)
.W Javie ten ciąg znaków jest obiektem. To wybór projektu.
Odwołania do obiektów mogą mieć wartość NULL i są zerowe, jeśli do obiektu nie jest przypisany żaden obiekt. Jeśli wywołasz taki obiekt, zgłoszony zostanie wyjątek NullPointerException. To standardowe zachowanie oo.
Projektanci Java zdecydowali się na posiadanie ciągów jako obiektu i stosowanie tych metod do zgłaszania wyjątków o zerowym wskaźniku, co otrzymujesz, jeśli chcesz, aby ciągi były obiektami.
Prawdopodobnie pomyśleli o tym i zdecydowali się uwzględnić zachowanie oo.
źródło
String.format
. (Nawiasem mówiąc, to samo w C #). Więc jeśli jest to wybór projektowy, nie może wynikać wyłącznie z faktu, że łańcuchy są obiektami i nie są stosowane konsekwentnie.Strings
klasie użyteczności, tak jak mamyArrays
klasę użyteczności ( chociaż rozumiem, że została stworzona z czystej konieczności, ponieważ tablice są dziwnym skrzyżowaniem prymitywów i obiektów: ) ) .. tak długo, jak był częścią standardowej Java i nie wymagał zależności.