A programozás világában kevés dolog olyan alapvető és mindennapi, mint a szövegek kezelése. Minden alkalmazás, weboldalak, mobilappok és asztali szoftverek egyaránt szövegekkel dolgoznak – felhasználói üzenetek, adatbázis-tartalmak, konfigurációs fájlok formájában. A Java programozási nyelvben ezek kezelése a String osztály segítségével történik, amely talán a leggyakrabban használt adattípus a fejlesztők számára.
A Java String egy objektum-orientált megközelítés a karakterláncok kezelésére, amely immutable (megváltozhatatlan) tulajdonságokkal rendelkezik. Ez azt jelenti, hogy egyszer létrehozott String objektum tartalma nem módosítható, minden művelet új objektumot hoz létre. A String osztály a java.lang csomagban található, így automatikusan elérhető minden Java programban külön import nélkül.
Ebben a részletes útmutatóban megismerkedhetsz a Java String működésének minden aspektusával. Megtudhatod, hogyan hozhatod létre és kezelheted a karakterláncokat, milyen hasznos metódusok állnak rendelkezésre, és hogyan optimalizálhatod a teljesítményt. Gyakorlati példákon keresztül láthatod a leggyakoribb használati eseteket, valamint tippeket kapsz a hatékony string kezeléshez.
Mi a Java String és hogyan működik?
A Java String karakterlánc reprezentáció, amely Unicode karakterek sorozatát tárolja. A String osztály a java.lang.Object osztályból származik, és számos hasznos metódust biztosít a szövegmanipulációhoz.
A String objektumok a heap memóriában tárolódnak, pontosabban a String Pool nevű speciális területen. Ez a mechanizmus lehetővé teszi, hogy azonos tartalmú stringek ugyanazt a memóriaterületet használják, ezzel optimalizálva a memóriahasználatot.
A karakterláncok immutable természete miatt minden módosítási művelet új String objektumot eredményez. Ez biztonsági és teljesítménybeli előnyökkel jár, de nagyobb memóriaigényt is jelenthet intenzív string manipuláció esetén.
String létrehozásának módjai
A Java-ban többféleképpen hozhatunk létre String objektumokat:
- Literál használata:
String name = "Java"; - new kulcsszó:
String name = new String("Java"); - char tömb konvertálása:
String name = new String(charArray); - byte tömb konvertálása:
String name = new String(byteArray); - StringBuilder/StringBuffer:
String name = builder.toString();
// Literál létrehozás - String Pool-ban tárolódik
String str1 = "Hello World";
// Konstruktor használata - külön objektum a heap-ben
String str2 = new String("Hello World");
// char tömb konvertálása
char[] chars = {'J', 'a', 'v', 'a'};
String str3 = new String(chars);
Alapvető String műveletek és metódusok
A String osztály gazdag metóduskészletet biztosít a karakterláncok kezeléséhez. Ezek a metódusok különböző kategóriákba sorolhatók: információ lekérdezés, manipuláció, összehasonlítás és keresés.
Az információ lekérdező metódusok lehetővé teszik a string tulajdonságainak megismerését. A length() metódus visszaadja a karakterek számát, míg az isEmpty() ellenőrzi, hogy üres-e a string.
A manipulációs metódusok új String objektumokat hoznak létre módosított tartalommal. Ide tartozik a substring(), replace(), toLowerCase() és toUpperCase() metódusok.
Gyakran használt String metódusok
| Metódus | Funkció | Példa |
|---|---|---|
| length() | Karakterek számának visszaadása | "Java".length() → 4 |
| charAt(int) | Adott pozíciójú karakter | "Java".charAt(0) → 'J' |
| substring(int, int) | Részstring kivágása | "Java".substring(1, 3) → "av" |
| indexOf(String) | String keresése | "Java".indexOf("va") → 2 |
| replace(char, char) | Karakter cseréje | "Java".replace('a', 'o') → "Jovo" |
| trim() | Szóközök eltávolítása | " Java ".trim() → "Java" |
String text = "Java Programming Language";
// Hossz lekérdezése
int length = text.length(); // 26
// Részstring kivágása
String sub = text.substring(0, 4); // "Java"
// Karakter keresése
int index = text.indexOf("Program"); // 5
// Nagybetűs verzió
String upper = text.toUpperCase(); // "JAVA PROGRAMMING LANGUAGE"
String összehasonlítás és egyenlőség vizsgálata
A karakterláncok összehasonlítása kritikus fontosságú a Java programozásban. A helyes összehasonlítási módszerek használata elkerüli a gyakori hibákat és biztosítja a program helyes működését.
Az == operátor referencia összehasonlítást végez, nem a tartalom alapján hasonlít össze. Ez azt jelenti, hogy két String objektum akkor egyenlő, ha ugyanarra a memóriacímre mutatnak.
Az equals() metódus tartalom alapú összehasonlítást végez, figyelembe véve a kis- és nagybetűk közötti különbséget. Az equalsIgnoreCase() metódus hasonlóan működik, de nem tesz különbséget a kis- és nagybetűk között.
"A String összehasonlításnál mindig az equals() metódust használd, soha az == operátort, kivéve ha kifejezetten referencia egyenlőséget szeretnél ellenőrizni."
Összehasonlítási metódusok részletesen
String str1 = "Java";
String str2 = "Java";
String str3 = new String("Java");
String str4 = "JAVA";
// Referencia összehasonlítás
System.out.println(str1 == str2); // true (String Pool miatt)
System.out.println(str1 == str3); // false (különböző objektumok)
// Tartalom összehasonlítás
System.out.println(str1.equals(str3)); // true
System.out.println(str1.equalsIgnoreCase(str4)); // true
// Lexikográfiai összehasonlítás
System.out.println(str1.compareTo("Java")); // 0
System.out.println(str1.compareTo("Python")); // negatív szám
A compareTo() metódus lexikográfiai sorrendet alkalmaz, és integer értéket ad vissza: negatívat, ha az első string kisebb, nullát, ha egyenlőek, és pozitívat, ha az első nagyobb.
String keresés és mintaillesztés
A karakterláncokban való keresés és mintaillesztés alapvető művelet minden programozási feladatban. A Java String osztály többféle megközelítést kínál a keresési feladatok megoldására.
Az indexOf() és lastIndexOf() metódusok lehetővé teszik karakterek vagy részstringek pozíciójának meghatározását. Ezek a metódusok -1 értéket adnak vissza, ha a keresett elem nem található.
A contains() metódus egyszerű boolean választ ad arra, hogy tartalmaz-e a string egy adott részstringet. A startsWith() és endsWith() metódusok pedig a string elejét és végét vizsgálják.
String sentence = "Java is a powerful programming language";
// Keresési műveletek
boolean hasJava = sentence.contains("Java"); // true
boolean startsWithJava = sentence.startsWith("Java"); // true
boolean endsWithLang = sentence.endsWith("language"); // true
// Pozíció meghatározása
int firstA = sentence.indexOf('a'); // 1
int lastA = sentence.lastIndexOf('a'); // 35
int powerfulPos = sentence.indexOf("powerful"); // 10
Reguláris kifejezések használata
A String osztály támogatja a reguláris kifejezések használatát is. A matches(), split() és replaceAll() metódusok regex pattern-eket fogadnak el paraméterként.
| Regex művelet | Metódus | Példa használat |
|---|---|---|
| Mintaillesztés | matches() | text.matches("\\d+") |
| Felosztás | split() | text.split("\\s+") |
| Csere | replaceAll() | text.replaceAll("\\d", "X") |
String phoneNumber = "123-456-7890";
String email = "user@example.com";
// Regex validáció
boolean isPhoneValid = phoneNumber.matches("\\d{3}-\\d{3}-\\d{4}");
boolean isEmailValid = email.matches("\\w+@\\w+\\.\\w+");
// String felosztása
String[] parts = phoneNumber.split("-");
// Eredmény: ["123", "456", "7890"]
String manipuláció és formázás
A karakterláncok manipulálása és formázása elengedhetetlen része a Java programozásnak. A String osztály számos metódust biztosít a szöveg átalakítására és formázására.
A replace() metóduscsalád lehetővé teszi karakterek vagy részstringek cseréjét. A replace() egyszerű cserét végez, míg a replaceAll() és replaceFirst() reguláris kifejezéseket használnak.
A trim() és kapcsolódó metódusok segítségével eltávolíthatjuk a felesleges szóközöket. A Java 11-től kezdve a strip(), stripLeading() és stripTrailing() metódusok Unicode-kompatibilis szóköz eltávolítást biztosítanak.
"A String immutable természete miatt minden manipulációs művelet új objektumot hoz létre, ami nagy mennyiségű művelet esetén memóriapazarláshoz vezethet."
Formázási lehetőségek
String template = "Hello, %s! Today is %s.";
String formatted = String.format(template, "Alice", "Monday");
// Eredmény: "Hello, Alice! Today is Monday."
// Számok formázása
double price = 123.456;
String priceFormatted = String.format("%.2f", price);
// Eredmény: "123.46"
// Különböző manipulációk
String original = " Java Programming ";
String cleaned = original.trim().toLowerCase().replace(" ", "_");
// Eredmény: "java_programming"
A String.format() metódus printf-stílusú formázást tesz lehetővé, amely különösen hasznos komplex szövegek összeállításánál.
StringBuilder és StringBuffer használata
Amikor gyakori string manipulációra van szükség, a hagyományos String objektumok használata ineffektív lehet az immutable természetük miatt. Ilyenkor a StringBuilder és StringBuffer osztályok jelentik a megoldást.
A StringBuilder mutable (módosítható) karakterlánc reprezentáció, amely hatékonyan kezeli a gyakori módosításokat. Nem thread-safe, ezért single-threaded környezetben ajánlott.
A StringBuffer hasonlóan működik, de thread-safe implementációval rendelkezik, ami multi-threaded alkalmazásokban teszi használhatóvá, bár kisebb teljesítményárat fizet érte.
// StringBuilder használata
StringBuilder sb = new StringBuilder();
sb.append("Java");
sb.append(" is");
sb.append(" awesome!");
String result = sb.toString(); // "Java is awesome!"
// Láncolt műveletek
StringBuilder chained = new StringBuilder()
.append("Start")
.append(" -> ")
.append("Middle")
.append(" -> ")
.append("End");
// Kapacitás kezelése
StringBuilder optimized = new StringBuilder(100); // előre allokált kapacitás
Teljesítmény összehasonlítás
A StringBuilder használata jelentős teljesítménybeli előnyt nyújt string konkatenáció esetén:
// Lassú megközelítés - új objektumokat hoz létre
String slow = "";
for (int i = 0; i < 1000; i++) {
slow += "text" + i;
}
// Gyors megközelítés - egy objektumot módosít
StringBuilder fast = new StringBuilder();
for (int i = 0; i < 1000; i++) {
fast.append("text").append(i);
}
String result = fast.toString();
"Nagy mennyiségű string konkatenációnál a StringBuilder használata akár 100-szoros sebességnövekedést is eredményezhet."
String Pool és memóriakezelés
A Java String Pool egy speciális memóriaterület a heap-ben, amely az azonos tartalmú string literálok megosztását teszi lehetővé. Ez a mechanizmus jelentős memóriamegtakarítást eredményez.
Amikor string literált használunk, a JVM először ellenőrzi, hogy létezik-e már ilyen tartalmú string a pool-ban. Ha igen, akkor a meglévő objektumra való referenciát adja vissza, ha nem, akkor új objektumot hoz létre és hozzáadja a pool-hoz.
A intern() metódus segítségével manuálisan is hozzáadhatunk stringeket a pool-hoz, ami memóriaoptimalizálást tesz lehetővé, különösen akkor, ha sok azonos tartalmú stringet használunk.
// String Pool működése
String s1 = "Hello"; // Pool-ban tárolva
String s2 = "Hello"; // Ugyanaz az objektum
String s3 = new String("Hello"); // Külön objektum a heap-ben
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
// Intern használata
String s4 = s3.intern();
System.out.println(s1 == s4); // true
Memória optimalizálási tippek
A hatékony string kezeléshez fontos megérteni a memóriahasználat jellemzőit:
- String literálok automatikusan a pool-ban tárolódnak
- A
new String()konstruktor mindig új objektumot hoz létre - Az
intern()metódus költséges művelet, óvatosan használd - Nagy alkalmazásokban figyeld a String Pool méretét
"A String Pool mérete korlátozott, túl sok intern() hívás OutOfMemoryError-hoz vezethet."
Encoding és karakterkészletek
A modern alkalmazások gyakran különböző karakterkészletekkel dolgoznak, ezért fontos megérteni a Java string encoding kezelését. A String objektumok belső reprezentációja UTF-16 encoding-ot használ.
Amikor byte tömböt konvertálunk String-gé vagy fordítva, meg kell adnunk a használni kívánt karakterkészletet. A platform alapértelmezett encoding-ja nem mindig megfelelő, különösen nemzetközi alkalmazások esetén.
A StandardCharsets osztály előre definiált konstansokat biztosít a leggyakoribb encoding-okhoz: UTF-8, UTF-16, ISO-8859-1, és US-ASCII.
import java.nio.charset.StandardCharsets;
// Byte tömb konvertálása különböző encoding-okkal
byte[] bytes = {72, 101, 108, 108, 111}; // "Hello" ASCII-ban
String utf8String = new String(bytes, StandardCharsets.UTF_8);
String isoString = new String(bytes, StandardCharsets.ISO_8859_1);
// String konvertálása byte tömbbé
String text = "Hello World";
byte[] utf8Bytes = text.getBytes(StandardCharsets.UTF_8);
byte[] asciiBytes = text.getBytes(StandardCharsets.US_ASCII);
// Unicode karakterek kezelése
String unicode = "Helló Világ! 🌍";
System.out.println(unicode.length()); // Karakterek száma (nem byte-ok!)
String validáció és hibakezelés
A megbízható alkalmazások fejlesztésekor elengedhetetlen a bemeneti adatok validálása. A String objektumok esetén különös figyelmet kell fordítani a null értékek és üres stringek kezelésére.
A null-safe programozás alapelve, hogy minden string műveletet megelőzzön null ellenőrzés. A modern Java verziók Optional osztálya és a null-safe operátorok segítségével elegánsan kezelhetjük ezeket az eseteket.
Az üres string ellenőrzése többféleképpen történhet: isEmpty(), isBlank() (Java 11+), vagy manuális hossz ellenőrzéssel.
// Null-safe string műveletek
public static boolean isValidString(String input) {
return input != null && !input.trim().isEmpty();
}
// Defensive programozás
public static String safeSubstring(String input, int start, int end) {
if (input == null) {
return null;
}
if (start < 0 || end > input.length() || start > end) {
throw new IllegalArgumentException("Invalid substring parameters");
}
return input.substring(start, end);
}
// Modern Java megközelítés (Java 11+)
public static String processString(String input) {
return Optional.ofNullable(input)
.filter(s -> !s.isBlank())
.map(String::trim)
.map(String::toLowerCase)
.orElse("default");
}
Gyakori validációs minták
// Email validáció
public static boolean isValidEmail(String email) {
return email != null &&
email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$");
}
// Telefonszám validáció
public static boolean isValidPhone(String phone) {
return phone != null &&
phone.replaceAll("[^\\d]", "").length() >= 10;
}
// Erős jelszó validáció
public static boolean isStrongPassword(String password) {
return password != null &&
password.length() >= 8 &&
password.matches(".*[A-Z].*") &&
password.matches(".*[a-z].*") &&
password.matches(".*\\d.*") &&
password.matches(".*[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?].*");
}
"A validáció nem csak a hibák elkerüléséről szól, hanem a felhasználói élmény javításáról is."
Teljesítmény optimalizálás és best practice-ek
A String kezelés optimalizálása kritikus fontosságú a nagy teljesítményű alkalmazások fejlesztésében. Számos technika és best practice segít a hatékony string műveletek megvalósításában.
Az objektum újrafelhasználás alapelve szerint kerüljük a felesleges String objektumok létrehozását. Használjunk string konstansokat, cache-eljük a gyakran használt értékeket, és válasszuk a megfelelő adatszerkezetet.
A StringBuilder pooling és kapacitás előzetes beállítása jelentős teljesítménynövekedést eredményezhet ismétlődő műveletek esetén.
// String konstansok használata
public class Constants {
public static final String EMPTY = "";
public static final String SPACE = " ";
public static final String NEWLINE = "\n";
public static final String COMMA = ",";
}
// StringBuilder optimalizálás
public static String buildLargeString(List<String> items) {
// Kapacitás becslése
int estimatedSize = items.size() * 20; // átlagos string hossz
StringBuilder sb = new StringBuilder(estimatedSize);
for (String item : items) {
sb.append(item).append(Constants.COMMA);
}
// Utolsó vessző eltávolítása
if (sb.length() > 0) {
sb.setLength(sb.length() - 1);
}
return sb.toString();
}
// String interning optimalizálás
private static final Map<String, String> STRING_CACHE = new ConcurrentHashMap<>();
public static String getCachedString(String input) {
return STRING_CACHE.computeIfAbsent(input, String::intern);
}
Teljesítmény mérési technikák
// Egyszerű benchmark
public static void benchmarkStringOperations() {
int iterations = 100000;
// String konkatenáció
long start = System.nanoTime();
String result = "";
for (int i = 0; i < iterations; i++) {
result += "a";
}
long stringTime = System.nanoTime() - start;
// StringBuilder
start = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < iterations; i++) {
sb.append("a");
}
String sbResult = sb.toString();
long sbTime = System.nanoTime() - start;
System.out.printf("String: %d ns, StringBuilder: %d ns%n",
stringTime, sbTime);
System.out.printf("StringBuilder is %.2fx faster%n",
(double) stringTime / sbTime);
}
"A StringBuilder használata string konkatenációnál exponenciálisan jobb teljesítményt nyújt a műveletek számának növekedésével."
Nemzetköziesítés és lokalizáció
A globális alkalmazások fejlesztésekor a string kezelés nemzetköziesítése (i18n) és lokalizációja (l10n) kulcsfontosságú. A Java beépített támogatást nyújt különböző nyelvek és kultúrák kezeléséhez.
A Locale osztály segítségével meghatározhatjuk a nyelvi és kulturális kontextust. Ez befolyásolja a string összehasonlítást, rendezést, és formázást.
A Collator osztály locale-aware string összehasonlítást tesz lehetővé, figyelembe véve a különböző nyelvek specifikus szabályait.
import java.text.Collator;
import java.util.Locale;
// Locale-specifikus műveletek
Locale hungarian = new Locale("hu", "HU");
Locale german = new Locale("de", "DE");
// Collator használata
Collator hunCollator = Collator.getInstance(hungarian);
Collator gerCollator = Collator.getInstance(german);
// Magyar ábécérend
String[] hunWords = {"alma", "ács", "béka", "búza"};
Arrays.sort(hunWords, hunCollator);
// Case-insensitive összehasonlítás
hunCollator.setStrength(Collator.SECONDARY);
int comparison = hunCollator.compare("Alma", "alma"); // 0
// Számformázás locale szerint
NumberFormat hunFormat = NumberFormat.getInstance(hungarian);
String hunNumber = hunFormat.format(1234.56); // "1 234,56"
NumberFormat usFormat = NumberFormat.getInstance(Locale.US);
String usNumber = usFormat.format(1234.56); // "1,234.56"
ResourceBundle használata
// Többnyelvű szövegek kezelése
ResourceBundle bundle = ResourceBundle.getBundle("messages", hungarian);
String greeting = bundle.getString("greeting"); // Helló!
// MessageFormat paraméteres üzenetekhez
String pattern = bundle.getString("welcome.message"); // "Üdvözöljük, {0}!"
String welcome = MessageFormat.format(pattern, "János"); // "Üdvözöljük, János!"
// Dátum és idő formázás
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
.withLocale(hungarian);
String date = LocalDate.now().format(formatter);
"A nemzetköziesítés nem utólagos feladat – a fejlesztés kezdetétől fogva tervezni kell rá."
Speciális String műveletek és algoritmusok
A haladó string manipuláció gyakran speciális algoritmusokat és technikákat igényel. Ezek közé tartoznak a string matching algoritmusok, a szöveg tokenizálása, és a komplex parsing műveletek.
A KMP (Knuth-Morris-Pratt) algoritmus hatékony string keresést tesz lehetővé nagy szövegekben. A Boyer-Moore algoritmus pedig jobbról balra történő keresésével gyakran még gyorsabb eredményt ér el.
A tokenizálás segítségével strukturált adatokat nyerhetünk ki szövegből. A Java StringTokenizer osztálya mellett a modern megközelítés a split() metódus használata reguláris kifejezésekkel.
// Egyszerű tokenizálás
String csvLine = "John,Doe,30,Engineer";
String[] tokens = csvLine.split(",");
// Komplex parsing reguláris kifejezéssel
String logEntry = "2023-12-01 14:30:25 [ERROR] Database connection failed";
Pattern logPattern = Pattern.compile("(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2}:\\d{2}) \\[(\\w+)\\] (.+)");
Matcher matcher = logPattern.matcher(logEntry);
if (matcher.find()) {
String date = matcher.group(1);
String time = matcher.group(2);
String level = matcher.group(3);
String message = matcher.group(4);
}
// String distance számítás (Levenshtein distance)
public static int levenshteinDistance(String a, String b) {
int[][] dp = new int[a.length() + 1][b.length() + 1];
for (int i = 0; i <= a.length(); i++) {
for (int j = 0; j <= b.length(); j++) {
if (i == 0) {
dp[i][j] = j;
} else if (j == 0) {
dp[i][j] = i;
} else {
dp[i][j] = Math.min(
Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1),
dp[i-1][j-1] + (a.charAt(i-1) == b.charAt(j-1) ? 0 : 1)
);
}
}
}
return dp[a.length()][b.length()];
}
Text processing utilities
// Word count implementáció
public static Map<String, Integer> wordCount(String text) {
return Arrays.stream(text.toLowerCase().split("\\W+"))
.filter(word -> !word.isEmpty())
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.summingInt(w -> 1)
));
}
// Palindrome ellenőrzés
public static boolean isPalindrome(String text) {
String cleaned = text.replaceAll("\\W", "").toLowerCase();
return cleaned.equals(new StringBuilder(cleaned).reverse().toString());
}
// Anagram ellenőrzés
public static boolean areAnagrams(String a, String b) {
if (a.length() != b.length()) return false;
char[] charsA = a.toLowerCase().toCharArray();
char[] charsB = b.toLowerCase().toCharArray();
Arrays.sort(charsA);
Arrays.sort(charsB);
return Arrays.equals(charsA, charsB);
}
Modern Java string funkciók
A Java újabb verziói számos hasznos string funkcióval bővültek, amelyek egyszerűbbé és hatékonyabbá teszik a szövegkezelést. A Java 11-től kezdve jelentős újítások jelentek meg.
A Java 11 bevezette a strip(), stripLeading(), stripTrailing() metódusokat, amelyek Unicode-aware whitespace eltávolítást végeznek. Az isBlank() metódus ellenőrzi, hogy a string üres vagy csak whitespace karaktereket tartalmaz.
A Java 15 szöveges blokkok (text blocks) támogatását hozta, amely többsoros stringek egyszerű kezelését teszi lehetővé. A Java 17 pedig további string manipulációs metódusokat adott hozzá.
// Java 11+ újdonságok
String text = " \t Hello World \n ";
// Unicode-aware trimming
String stripped = text.strip(); // "Hello World"
String leadingStripped = text.stripLeading(); // "Hello World \n "
String trailingStripped = text.stripTrailing(); // " \t Hello World"
// Blank ellenőrzés
boolean isEmpty = "".isBlank(); // true
boolean isBlank = " \t\n ".isBlank(); // true
boolean hasContent = "Hello".isBlank(); // false
// String ismétlés
String repeated = "Ha".repeat(3); // "HaHaHa"
// Lines stream
String multiline = "Line1\nLine2\nLine3";
List<String> lines = multiline.lines()
.collect(Collectors.toList());
// Java 15+ Text Blocks
String jsonTemplate = """
{
"name": "%s",
"age": %d,
"city": "%s"
}
""";
String json = String.format(jsonTemplate, "John", 30, "New York");
Streaming API és string műveletek
// String műveletek streamekkel
List<String> words = List.of("apple", "banana", "cherry", "date");
// Szűrés és transzformáció
List<String> processed = words.stream()
.filter(word -> word.length() > 4)
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
// String joining
String joined = words.stream()
.collect(Collectors.joining(", ", "[", "]"));
// Eredmény: "[apple, banana, cherry, date]"
// Karakterek elemzése
String text = "Hello World";
Map<Character, Long> charFreq = text.chars()
.filter(ch -> ch != ' ')
.mapToObj(ch -> (char) ch)
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
));
"A text blocks használata jelentősen javítja a többsoros stringek olvashatóságát és karbantarthatóságát."
Hibakeresés és troubleshooting
A string műveletek hibakeresése gyakran kihívást jelent, különösen komplex alkalmazásokban. A leggyakoribb problémák a null pointer exception-ök, encoding hibák, és teljesítménybeli problémák.
A null safety biztosítása érdekében mindig ellenőrizzük a bemeneti paramétereket. Használjunk defensive programming technikákat és Optional wrapper-eket ahol lehetséges.
Az encoding problémák diagnosztizálásához hasznos a byte-level vizsgálat és a különböző karakterkészletek tesztelése.
// Debug utility metódusok
public static void debugString(String str) {
if (str == null) {
System.out.println("String is null");
return;
}
System.out.printf("String: '%s'%n", str);
System.out.printf("Length: %d%n", str.length());
System.out.printf("Empty: %s%n", str.isEmpty());
System.out.printf("Blank: %s%n", str.isBlank()); // Java 11+
// Karakterek részletes vizsgálata
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
System.out.printf(" [%d]: '%c' (U+%04X)%n", i, ch, (int) ch);
}
// Byte reprezentáció
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
System.out.printf("UTF-8 bytes: %s%n", Arrays.toString(bytes));
}
// Memory usage monitoring
public static void monitorStringMemory() {
Runtime runtime = Runtime.getRuntime();
long beforeMemory = runtime.totalMemory() - runtime.freeMemory();
// String műveletek végrehajtása
performStringOperations();
System.gc(); // Garbage collection kényszerítése
long afterMemory = runtime.totalMemory() - runtime.freeMemory();
long memoryUsed = afterMemory - beforeMemory;
System.out.printf("Memory used: %d bytes%n", memoryUsed);
}
Teljesítmény profilozás
// Egyszerű profiling
public static class StringProfiler {
private static final Map<String, Long> timings = new HashMap<>();
public static void startTiming(String operation) {
timings.put(operation, System.nanoTime());
}
public static void endTiming(String operation) {
Long startTime = timings.remove(operation);
if (startTime != null) {
long duration = System.nanoTime() - startTime;
System.out.printf("%s took: %.2f ms%n",
operation, duration / 1_000_000.0);
}
}
}
// Használat
StringProfiler.startTiming("string-concat");
String result = performStringConcatenation();
StringProfiler.endTiming("string-concat");
Biztonság és string kezelés
A biztonságos string kezelés kritikus fontosságú a modern alkalmazásokban. A string-alapú sebezhetőségek, mint az SQL injection, XSS, és path traversal támadások megelőzése alapvető biztonsági követelmény.
Az input sanitization során minden felhasználói bemenetet ellenőrizni és tisztítani kell. A output encoding biztosítja, hogy a kimeneti adatok biztonságosan jelenjenek meg különböző kontextusokban.
A sensitive data handling során kerülni kell a jelszavak és más érzékeny információk string objektumokban való tárolását, helyette char array-eket használjunk.
// Input sanitization
public static String sanitizeInput(String input) {
if (input == null) return null;
return input.trim()
.replaceAll("[<>\"'&]", "") // XSS karakterek eltávolítása
.replaceAll("\\p{Cntrl}", "") // Kontroll karakterek
.substring(0, Math.min(input.length(), 255)); // Hossz korlátozás
}
// SQL injection védelem
public static String escapeSql(String input) {
if (input == null) return null;
return input.replace("'", "''")
.replace("\\", "\\\\")
.replace("%", "\\%")
.replace("_", "\\_");
}
// Path traversal védelem
public static boolean isValidPath(String path) {
if (path == null) return false;
String normalizedPath = Paths.get(path).normalize().toString();
return !normalizedPath.contains("..") &&
!normalizedPath.startsWith("/") &&
!normalizedPath.contains("\\");
}
// Secure password handling
public static boolean verifyPassword(char[] password, String hash) {
try {
// Jelszó ellenőrzés char array-jel
String passwordStr = new String(password);
boolean isValid = BCrypt.checkpw(passwordStr, hash);
// Jelszó törlése memóriából
Arrays.fill(password, '\0');
return isValid;
} catch (Exception e) {
Arrays.fill(password, '\0'); // Cleanup hiba esetén is
return false;
}
}
"Soha ne tárold jelszavakat String objektumban – használj char array-t és töröld a tartalmat használat után."
Mik a fő különbségek a String és StringBuilder között?
A String objektumok immutable (megváltozhatatlan) tulajdonsággal rendelkeznek, ami azt jelenti, hogy minden módosítás új objektumot hoz létre. Ezzel szemben a StringBuilder mutable (módosítható), így hatékonyan kezeli a gyakori string manipulációkat anélkül, hogy új objektumokat hozna létre minden művelettel.
Hogyan működik a String Pool a Java-ban?
A String Pool egy speciális memóriaterület a heap-ben, ahol az azonos tartalmú string literálok tárolódnak. Amikor string literált használunk, a JVM ellenőrzi, hogy létezik-e már ilyen string a pool-ban. Ha igen, akkor a meglévő objektumra való referenciát adja vissza, ezzel optimalizálva a memóriahasználatot.
Mikor használjam az equals() metódust az == operátor helyett?
Az equals() metódust mindig akkor használd, amikor a string tartalmát szeretnéd összehasonlítani. Az == operátor csak referencia egyenlőséget vizsgál, vagyis azt, hogy két változó ugyanarra a memóriacímre mutat-e. A tartalom-alapú összehasonlításhoz mindig az equals() vagy equalsIgnoreCase() metódust válaszd.
Hogyan kezeljem a null értékeket string műveleteknél?
Minden string műveletet null ellenőrzéssel kezdj. Használhatsz defensive programming technikákat, Optional wrapper-eket, vagy utility metódusokat a null-safe műveletek megvalósításához. A modern Java verziókban az Optional.ofNullable() metódus elegáns megoldást nyújt.
Milyen teljesítménybeli szempontokat kell figyelembe venni?
Nagy mennyiségű string konkatenációnál használj StringBuilder-t a hagyományos + operátor helyett. Kerüld a felesleges String objektumok létrehozását, használj string konstansokat, és figyeld a String Pool méretét. Az intern() metódust óvatosan alkalmazd, mert költséges művelet.
Hogyan kezelem a különböző karakterkészleteket?
Mindig explicit módon add meg a karakterkészletet byte array konverziók során. Használd a StandardCharsets osztály konstansait (UTF_8, UTF_16, stb.) a platform-független működés érdekében. Unicode karakterek esetén figyelj a string hosszára, mert az nem egyezik meg a byte-ok számával.
