Range w Javie. Czyli kilka słów o zakresie.

range-java

Programuję w Javie, ale poznaję też kolejne języki i często zastanawiam się nad tym co inny język oferuje, a czego Java nie ma. Jedną z takich rzeczy jest zapisywanie zakresu. W niektórych językach jest to bardzo proste i odgórnie określone. Na przykład w Kotlinie można użyć gotowych klas range dla typów porządkowanych np. IntRange czy CharRange. Przykład poniżej:

fun main() {
    sum(1..2)
    sum(1..5) // 15
    sum(1.rangeTo(5)) // 15
    sumCharValue('a'..'e') // 495
    sumCharValue('a'.rangeTo('e')) // 495
}

fun sum(r: IntRange): Int {
    var sum = 0
    for (i in r) {
        sum += i
    }
    return sum
}

fun sumCharValue(r: CharRange): Int {
    var sum = 0;
    for (i in r) {
        sum += i.toInt()
    }
    return sum
}

Zapis 1..5 jak również 1.rangeTo(5) to różny zapis tego samego obiektu typu IntRange. Dzięki takiemu rozwiązaniu możemy uniknąć dodawania dwóch parametrów do metody, ale przede wszystkim mamy jasność, że dany zakres stanowi przedział obustronnie domknięty, bo tak zdefiniowana jest dana klasa w języku Kotlin. Czyli zarówno wartość 1 jak i 5 są częścią zakresu 1..5.

W Pythonie z kolei możemy użyć funkcji range(), z parametrami start, stop step. Co ciekawe tutaj przedział jest już prawostronnie otwarty, więc dla zakresu range(1, 5) wartość 1 jest jeszcze w granicach zakresu, lecz 5 już nie.

Zakres występuje jeszcze w innych językach, temat jest też dostępny w Wikipedii.

Zakres w Javie

Przejdźmy do sedna, bo dlaczego o tym wszystkim wspomniałem? Otóż ostatnio zacząłem się zastanawiać nad brakiem jasno zdefiniowanego obiektu typu range w Javie przy okazji użycia metod klasy Random. Metoda Random.nextInt() przyjmuje jako parametr tylko górną granicę zakresu, uznając domyślnie jego początek za zero. I tu zakres jest lewostronnie domknięty, a prawostronnie otwarty. Szukając liczby z zakresu innego, niż taki zaczynający się od zera musiałem wprowadzić takie modyfikacje do kodu, jak poniżej:

int start = 123_456;
int stop = 999_999;
Random random = new Random();
int value = random.nextInt(stop - start) + start;

Co jednak ciekawe nawet sama klasa Random używa wewnętrznie metody, która robi dokładnie to co ja.

final int internalNextInt(int origin, int bound) {
    if (origin < bound) {
        int n = bound - origin;
        if (n > 0) {
            return nextInt(n) + origin;
...

I właśnie ten przykład dał mi do myślenie, że może gdyby w Javie zakres zapisywało się za pomocą jakieś klasy Range, to moze od samego początku twórcy klasy Random zamiast użyć metody nextInt(int bound) użyliby od razu nextInt(Range r). To tylko taka moja dywagacja.

I uprzedzając pytania, oczywiście są biblioteki, których metody pozwalają zdefiniować początek przedziału, jak również można sobie samemu taką klasę napisać. Przykład poniżej:

public class Range {

    int start;
    int stop;

    public Range(int start, int stop) {
        this.start = start;
        this.stop = stop;
    }

    public boolean contains(int x) {
        return x >= start && x <= stop;
    }
}

Jeżeli macie swoje przemyślenia odnośnie zakresów w Javie dajcie znać w komentarzach.

PS. Staram się używać zamiennie polskich i oryginalnych nazw. W programowaniu angielski jest podstawowym językiem i często w ogóle nie używa się polskich określeń. Czasem polskie nazwy potrafią wręcz wprawić w zakłopotanie, jednak spotykam się z nimi w literaturze czy na innych blogach, więc taka zamienność nazw mam nadzieję, że będzie jedynie pomocna dla osób zaczynających programować.

Range w Javie. Czyli kilka słów o zakresie.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Przewiń do góry