Stringovi u Javi: String i StringBuilder

Lekcija 7 od 16 · Java

Tekst se u Javi čuva u objektima klase String. U ovoj lekciji su najvažnije metode za rad sa tekstom, poređenje stringova, rad sa pojedinačnim znakovima, deljenje teksta na reči i klasa StringBuilder za brzo sastavljanje teksta.

Pre nego što počneš: potrebno predznanje – nizovi, petlje.
Kako da učiš: svaki primer prekucaj i pokreni, a zadatke na kraju prvo reši sam/a; uputstvo i rešenje otvori tek posle toga. Svi programi su u Javi (Java 17 ili novija); svaki je preveden i pokrenut i daje navedeni izlaz.

String: kreiranje, dužina i znakovi

String je niz znakova. Dužina se dobija metodom length(), a znak na poziciji i metodom charAt(i). Pozicije se broje od 0.

public class Main {
    public static void main(String[] args) {
        String rec = "Programiranje";
        System.out.println("Duzina: " + rec.length());
        System.out.println("Prvi znak: " + rec.charAt(0));
        System.out.println("Poslednji znak: " + rec.charAt(rec.length() - 1));

        // prolaz kroz sve znakove
        int samoglasnika = 0;
        for (int i = 0; i < rec.length(); i++) {
            char c = Character.toLowerCase(rec.charAt(i));
            if ("aeiou".indexOf(c) >= 0)
                samoglasnika++;
        }
        System.out.println("Samoglasnika: " + samoglasnika);
    }
}

Pristup poziciji van opsega (npr. charAt(13) za reč od 13 slova) izaziva grešku StringIndexOutOfBoundsException.

Najvažnije metode klase String

MetodaRezultat za s = "Dobar dan"
s.toUpperCase()"DOBAR DAN"
s.toLowerCase()"dobar dan"
s.indexOf("dan")6 (−1 ako ne postoji)
s.contains("bar")true
s.substring(6)"dan" – od pozicije 6 do kraja
s.substring(0, 5)"Dobar" – pozicije 0…4
s.replace('a', 'o')"Dobor don"
s.startsWith("Do")true
" x ".trim()"x" – bez razmaka na krajevima
s.isEmpty()false

String je nepromenljiv (immutable): nijedna metoda ne menja postojeći string, nego vraća novi. Zato se rezultat mora sačuvati:

public class Main {
    public static void main(String[] args) {
        String s = "Dobar dan";
        s.toUpperCase();                 // rezultat se gubi – s se ne menja
        System.out.println(s);
        s = s.toUpperCase();             // novi string se dodeljuje promenljivoj
        System.out.println(s);
        System.out.println(s.substring(0, 5) + "!" + " (" + s.indexOf("DAN") + ")");
    }
}

Poređenje stringova: equals, a ne ==

Operator == kod objekata proverava da li su to isti objekti u memoriji, a ne da li imaju isti sadržaj. Sadržaj se poredi metodom equals, a abecedni redosled metodom compareTo.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String a = sc.next();                 // korisnik unese: java
        String b = "java";

        System.out.println(a == b);           // false: različiti objekti
        System.out.println(a.equals(b));      // true: isti sadržaj
        System.out.println("Java".equalsIgnoreCase(b));   // true: zanemaruje velika/mala slova

        // compareTo: negativno ako je prvi ispred u abecedi, 0 ako su jednaki, pozitivno inače
        System.out.println("Ana".compareTo("Marko") < 0);  // true
        System.out.println("Zoran".compareTo("Ana") > 0);  // true
    }
}

Ovo je jedna od najčešćih grešaka početnika: if (odgovor == "da") često ne radi. Uvek piši if (odgovor.equals("da")).

Rad sa znakovima: klasa Character

Klasa Character ima metode za proveru i promenu jednog znaka: isDigit, isLetter, isUpperCase, toUpperCase… Cifra se pretvara u broj oduzimanjem znaka '0'.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String lozinka = sc.next();
        int cifre = 0, velika = 0, mala = 0, zbirCifara = 0;
        for (char c : lozinka.toCharArray()) {     // for-each kroz niz znakova
            if (Character.isDigit(c)) {
                cifre++;
                zbirCifara += c - '0';             // '7' - '0' = 7
            } else if (Character.isUpperCase(c)) {
                velika++;
            } else if (Character.isLowerCase(c)) {
                mala++;
            }
        }
        System.out.println("cifre=" + cifre + " velika=" + velika + " mala=" + mala + " zbir cifara=" + zbirCifara);
        boolean jaka = lozinka.length() >= 8 && cifre > 0 && velika > 0 && mala > 0;
        System.out.println(jaka ? "Jaka lozinka" : "Slaba lozinka");
    }
}

Deljenje teksta na reči: split

Metoda split deli string na niz delova po zadatom razdvajaču. Razdvajač je regularni izraz: " " je jedan razmak, a "\\s+" jedan ili više razmaka.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String recenica = sc.nextLine().trim();
        String[] reci = recenica.split("\\s+");      // jedan ili više razmaka

        System.out.println("Broj reci: " + reci.length);
        String najduza = "";
        for (String r : reci)
            if (r.length() > najduza.length())
                najduza = r;
        System.out.println("Najduza rec: " + najduza);

        // sastavljanje nazad: String.join
        System.out.println(String.join("-", reci));
    }
}

Za brojeve u jednom redu: String[] d = red.split(" "); int x = Integer.parseInt(d[0]);.

StringBuilder: brzo sastavljanje teksta

Pošto je String nepromenljiv, svako s = s + "x" pravi novi string i kopira ceo stari sadržaj. U petlji sa 100 000 ponavljanja to je sporo. Klasa StringBuilder čuva tekst koji se može menjati: append dodaje na kraj, reverse obrće, insert umeće, toString vraća String.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();

        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= n; i++) {
            sb.append(i);
            if (i < n) sb.append(", ");
        }
        System.out.println(sb);                       // println poziva toString()

        String rec = sc.next();
        String obrnuto = new StringBuilder(rec).reverse().toString();
        System.out.println(obrnuto);
        System.out.println(rec.equalsIgnoreCase(obrnuto) ? "palindrom" : "nije palindrom");
    }
}

Zadaci za vežbu

Za svaki zadatak postoji primer, uputstvo i rešenje. Rešenja su provereno tačna na primerima iz teksta.

ZADATAK 01Težina: srednje

Šifra pomeranjem

Cezarova šifra pomera svako slovo engleske abecede za k mesta (posle z ide a); ostali znakovi se ne menjaju, a velika slova ostaju velika. Učitava se k (0–25), pa jedan red teksta. Ispisati šifrovan tekst.

Primer

Ulaz

3
Zdravo, svete!

Izlaz

Cgudyr, vyhwh!
ZADATAK 02Težina: srednje

Brojanje reči

Učitava se jedan red teksta i jedna reč r (u sledećem redu). Ispisati koliko puta se reč r pojavljuje u tekstu kao cela reč, bez obzira na velika i mala slova. Znakovi interpunkcije (.,!?) se zanemaruju.

Primer

Ulaz

Java je jezik. JAVA radi svuda, java!
java

Izlaz

3
ZADATAK 03Težina: teže

Kompresija

Učitava se reč od malih slova. Svaku grupu uzastopnih istih slova zameniti slovom i brojem ponavljanja (ako je broj 1, ispisuje se samo slovo). Npr. aaabccdddd → a3bc2d4.

Primer 1

Ulaz

aaabccdddd

Izlaz

a3bc2d4

Primer 2

Ulaz

abc

Izlaz

abc
Česte greške i saveti
  • Stringove poredi sa equals, nikako sa ==.
  • Metode Stringa ne menjaju string – sačuvaj rezultat: s = s.trim();.
  • substring(a, b) uzima znakove od a do b − 1; dužina rezultata je b − a.
  • U petlji koja sastavlja dug tekst koristi StringBuilder, ne +.
  • U split tačka mora da se piše "\\.", jer je obična tačka u regularnom izrazu „bilo koji znak“.

Proveri znanje

Otvori kviz

Stringovi u Javi

1. Kako se proverava da li stringovi a i b imaju isti sadržaj?




2. Šta vraća "Java".substring(1, 3)?




3. Šta je rezultat "abc".indexOf('x')?




4. Zašto se u petlji koristi StringBuilder?