Trinn 1 i Java-delen av Kodeklubben høsten 2015 handler om å bli vant med å programmere enkle Java-programmer, med utgangspunkt i at du kan litt Python fra før.

På denne siden forklarer vi litt om forskjellen mellom Python og Java, med noen kode-eksempler. Først er det et lite eksempel for å komme igang og lenger ned et større et. Nederst på siden etter det største kode-eksemplet er det en oppgave (med deloppgaver), som vi anbefaler deg å prøve på.

Det meste er likt, men forskjellig...

Det meste av det du kan om programmering med Python er nyttig når du skal lære Java. F.eks. har Java også variabler, tall- og tekstverdier, funksjoner (kalles metoder i Java), og kontrollstrukturer (nøkkelord som styrer programmet) som if, while og for. Samtidig er veldig mange av detaljene i et Java-program forskjellig fra et tilsvarende Python-program. F.eks. så bruker Python : (kolon) etter if og else og innrykk i hver gren, mens Java bruker ( ) rundt if-betingelsen og { } rundt koden i hver gren (hvis en trenger mer enn én setning) og innrykket spiller ingen rolle. Det er også noen mer vesentlige forskjeller, som at Java krever at en deklarerer variabler og hvilken type verdi de kan ha, før de brukes, og generelt har strengere regler for hva slags kode som kan være hvor i en programfil.

La oss først se på et lite eksempel, før vi tar et fra Python-delen av Kodeklubben fra våren 2014.

Python
print('Hvor gammel er du?')
age = int(input())
print('Neste år blir du ' + str(age + 1) + ' år!')
Java
System.out.println("Hvor gammel er du?");
Scanner scanner = new Scanner(System.in);
int age = scanner.nextInt();
System.out.println("Neste år blir du " + (age + 1) + " år!");

I eksemplene over, skrives det ut en tekst, et tall leses inn og en ny (beregnet) tekst skrives ut. Det er lett å se sammenhengen mellom Python- og Java-versjonene, selv om mange detaljer er forskjellig:

  • Python bruker print for utskrift (til konsollet), mens Java bruker System.out.println.
  • Java bruker ; (semikolon) etter hver setning.
  • Python bruker input for å lese inn tekst og konverterer til tall med int, mens Java bruker en Scanner og nextInt for å lese inn et tall.
  • Både Python og Java bruker + for å sette sammen tekst(biter) til en ny tekst, men Python må konvertere tall til tekst med str først.
En viktig forskjell er imidlertid ikke vist her, nemlig at Java-koden over ikke kan utføres som et helt program, men trenger litt kode rundt. Nedenfor er to varianter vist, som begge er komplette programmer:

 

Kode i main-metode
class Eksempel {
	public static void main(String[] args) {
		System.out.println("Hvor gammel er du?");
		Scanner scanner = new Scanner(System.in);
		int age = scanner.nextInt();
		System.out.println("Neste år blir du " + (age + 1) + " år!");
	}
}

Enkleste variant for å gjøre koden komplett.

Kode i run-metode, som kjøres fra main-metode
class Eksempel {
	void run() {
		System.out.println("Hvor gammel er du?");
		Scanner scanner = new Scanner(System.in);
		int age = scanner.nextInt();
		System.out.println("Neste år blir du " + (age + 1) + " år!");
	}
	public static void main(String[] args) {
		Eksempel1 program = new Eksempel1();
		program.run();
	}
}

Litt mer komplisert, men litt mer generell teknikk (som vi skal se på under).

 

Fra Python til Java

Nå skal vi se på forskjellen mellom Python og Java med utgangspunkt i Python-leksjonen fra våren 2014 om koding av tekst. Dersom du ikke husker hva det dreide seg om så finner du hele denne leksjonen her: lesson03.pdf

For å gjøre det litt lettere å "oversette" Python-koden til Java, så gjør vi først en liten omstrukturering av Python-koden. Versjon 1 under til venstre er originalkoden fra pdf-filen, mens vi i versjon 2 har samlet (det meste av) koden som ikke allerede er inni en funksjon, i run()-funksjonen. Den eneste koden utenfor funksjonene er håndtering av variabler som er greit at alle funksjonene bruker, typisk såkalte konstanter, som først initialiseres og siden bare leses. I tillegg legger vi til et kall til run()-funksjonen helt til slutt.

Versjon 1
alphabet = "abcdefghijklmnopqrstuvwxyz"

def encode(letter, secret):
    pos = alphabet.find(letter)
    newpos = (pos + secret)
    if newpos >= 26:
        newpos = newpos - 26
    return alphabet[newpos]

def decode(letter, secret):
    pos = alphabet.find(letter)
    newpos = (pos - secret)
    if newpos < 0:
        newpos = newpos + 26
    return alphabet[newpos]

secret = 17
message = "hello world"
output = ""
for character in message:
    if character in alphabet:
        output = output + encode(character, secret)
    else:
        output = output + character
    print(output)

secret = 17
message = "yvccf nficu"
output = ""
for character in message:
    if character in alphabet:
        output = output + decode(character, secret)
    else:
        output = output + character
    print(output)
Versjon 2
# alphabet-variablen ligger utenfor funksjonene,
# slik at den kan brukes av dem alle
alphabet = "abcdefghijklmnopqrstuvwxyz"

# encode- og decode-funksjonene er som før
def encode(letter, secret):
    pos = alphabet.find(letter)
    newpos = (pos + secret)
    if newpos >= 26:
        newpos = newpos - 26
    return alphabet[newpos]

def decode(letter, secret):
    pos = alphabet.find(letter)
    newpos = (pos - secret)
    if newpos < 0:
        newpos = newpos + 26
    return alphabet[newpos]

# run()-funksjonen samler koden som tidligere lå utenfor funksjonene.
# Dette er det en gjerne kaller "hovedprogrammet".
# Navnet spiller egentlig ingen rolle, men
# run er lett å kjenne igjen.
def run():
    message = "hello world"
    secret= 17
    output = ""
    for character in message:
        if character in alphabet:
            output = output + encode(character, secret)
        else:
            output = output + character
        print(output)
    message = "yvccf nficu"
    output = ""
    for character in message:
        if character in alphabet:
            output = output + decode(character, secret)
        else:
            output = output + character
        print(output)

# Her kalles "hovedprogram"-funksjonen.
run()

Under er Java-versjonen av samme program. Kopier gjerne koden inn i et kodingsprosjekt i Eclipse med lim inn-funksjonen, så det blir enklere å leke seg litt med den. Lenger ned går vi gjennom de viktigste forskjellene mellom Python og Java, omtrent slik de dukker opp i kode-eksemplet. Nederst er det en oppgave i fem deler som bygger på denne koden. Til slutt er det en oppgave som vi anbefaler deg å se på, for å se at du har skjønt det viktigste.

Java-versjon
package trinn1;

class EncodeDecode {
    String alphabet = "abcdefghijklmnopqrstuvwxyz";

	char encode(char letter, int secret) {
        int pos = alphabet.indexOf(letter);
        int newpos = (pos + secret);
        if (newpos >= 26) {
            newpos = newpos - 26;
        }
        return alphabet.charAt(newpos);
    }
    
    char decode(char letter, int secret) {
        int pos = alphabet.indexOf(letter);
        int newpos = (pos - secret);
        if (newpos < 0) {
            newpos = newpos + 26;
        }
        return alphabet.charAt(newpos);
    }

	void run() {
        String message = "hello world";
        int secret = 17;
        String output = "";
        for (int i = 0; i < message.length(); i = i + 1) {
            char character = message.charAt(i);
            if (alphabet.indexOf(character) >= 0)
                output = output + encode(character, secret);
            else
                output = output + character;
            System.out.println(output);
        }
        message = "yvccf nficu";
        output = "";
        for (int i = 0; i < message.length(); i++) {
            char character = message.charAt(i);
            if (alphabet.indexOf(character) >= 0)
                output = output + decode(character, secret);
            else
                output = output + character;
            System.out.println(output);
        }
    }
    
    public static void main(String[] args) {
        EncodeDecode program = new EncodeDecode();
		program.run();
	}
}
Klasser og navngiving

All kode i et Java-program ligger i såkalte klasser, altså inni en class-blokk. Klasser må ha et navn, og her har vi valgt EncodeDecode. I tillegg ligger klasser gjerne i en slags mapper som kalles pakke, og den angis med package-nøkkelordet. Her har vi valgt pakkenavnet trinn1. Sammen utgjør pakke- og klassenavnet det fulle navnet til klassen, som her er trinn1.EncodeDecode.

Typer må deklareres

Java krever at alle variabler deklareres (og gjerne initialiseres) før de brukes. Når vi her skriver String alphabet, så betyr det variablen alphabet bare kan ha verdier som er av type String. Her intialiseres samtidig alphabet til en bestemt String bestående av alle bokstaver i (det engelske) alfabetet. Fordelen med å angi typen er at Java kan sjekke at vi bare gjør lovlige ting med variablen. F.eks. kan vi finne lengden til den ved å skrive alphabet.length(), men vi kan ikke dele den med 2 som i alphabet / 2.

Bruk av semikolon

Variabel-deklarasjonen avsluttes med ; (semikolon), og dette er typisk for Java, hvor nesten alle setninger avsluttes med semikolon. Sammen med kravet om typer overalt, er dette det som irriterer Python-programmerere mest, fordi det virker så unødvendig og er så lett å glemme.

Kodeblokker og { }

Mens en i Python bruker : og innrykk for å angi koden som hører til inni funksjoner (også i if og for), så bruker en i Java { } (kalt krøllparenteser) rundt koden. Hvis det blir rot med krøllparentesene så blir Java fort forvirret, så det må en være nøye med. Java bryr seg ikke om innrykk, men det er viktig for å gjøre koden mer lettlest for oss, og de fleste Java-editorer ordner det for oss, basert på krøllparentesene.

Metoder

Funksjoner kalles metoder i Java, og som med variabler, så må en deklarere hva slags type verdi den returnerer ("regner ut") og hvilke typer parametrene har. Vi ser at encode-metoden tar inn en char, som er typen for tegn, og en int, som er typen for heltall, og returnerer en char. Igjen er poenget at når typene er angitt slik, så kan Java sjekke at vi ikke prøver å kalle encode med gale (typer) verdier og at vi ikke prøver å bruke resultatet feil. Denne sjekken kan gjøres mens vi skriver koden, altså lange før den kjøres, og tanken er at selv om det blir litt mer å tenke på og skrive, så sparer en tid ved å unngå feil.

Kalle metoder med dott-notasjonen

Som i Python, så bruker Java . (punktum eller dott) for å kalle funksjoner på en verdi.

String-metoder

alphabet.indexOf(letter) finner posisjonen til letter i alphabet og gjør i praksis det samme som alphabet.find(letter) i Python. Dette er egentlig nokså typisk: Python og Java har mange av de samme funksjonene, men har valgt forskjellig navn. Når indexOf-metoden kan kalles på denne måten, så er det fordi String-typen på en måte har metoden "inni" seg. En sier gjerne at en "ber" String utføre metoden. Her er noen andre nyttige String-metoder:

  • charAt(pos)charAt returnerer tegnet på posisjonen angitt av argumentet, som må være et heltall. Denne metoden brukes i return-setningen til både encode og decode.
  • length() returnerer lengden (antall tegn i String-en). Denne metoden brukes i for-løkka (se lengre ned) for å løpe gjennom alle tegnene i meldingen.
  • indexOf(tegn): returnerer posisjonen til tegn (en char) i String-en. Dersom tegnet finnes flere steder, så er det den med lavest posisjon som gjelder. Dersom tegn ikke finnes, så returneres -1. Sånn sett kan indexOf brukes litt som Python sin contains-funksjon.
Prosedyrer og void-typen

Hensikten med run-metoden er å skrive ut informasjon, ikke å beregne en verdi. En bruker da void som retur-type, og en trenger ikke ha noen return-setning. En slik metode kalles en prosedyre, og dette er typisk for metoder som samler koden som utgjøre hovedprogrammet (og som vi derfor kaller hovedprogram-metoder).

Forgreining med if

Java sin if fungerer som Python sin, men den skrives litt annerledes. Som oftest samles setninger i hver grein med { }, men dersom en som her bare har én setning i en grein, så slipper en krøllparentesene. Les mer om forgreining med if her: if-kontrollstrukturen

for-løkker

Som i Python, å kan en bruke en for-løkke for å gå gjennom alle elementene i en String. Java har to varianter av for, og den som brukes her er den mest generelle (og tungvinte). Løkka består av fire deler, slik: for (initialisering; betingelse; steg) { setninger }

  1. Initialsering: Her deklareres i som løkke-variabel. Den skal brukes for å løpe gjennom alle lovlige posisjoner i message.
  2. Betingelsen bestemmer om løkke skal ta en runde til. Her skjer det så lenge i er mindre enn antall bokstaver i teksten.
  3. Steg-delen brukes til å drive løkka fremover, og må stemme med betingelsen for å unngå evig løkke. Her økes i med 1, slik at en løper gjennom message tegn for tegn.
  4. Setningene inni løkka utføres i hver runde og vil typisk inneholde kode for å behandle ett data-element. Her hentes tegnet på i-posisjonen ut, den dekodes og legges til output-variabelen.

Les mer om for-setninger, som brukes for å behandle data her: Data-drevne løkker

Utskrift til skjerm med System.out.println.

I Java gjøres utskrift til skjerm ved å bruke System.out.println (evt. System.out.print, som ikke avslutter med linjeskift). System.out er på en måte navnet til konsollet, og en ber den skrive ut ved å kalle println- eller print med det som skal skrives ut som argument.

Les om toString()-metoden, for å forstå hvordan println gjør om verdier til tekst. Les også om hvordan motstykket til output, som er input, ofte gjøres i Java: Input med Scanner-objekter.

Kjøring av programmer

I motsetning til Python, så kan en ikke legge et kall til run() i bunnen av fila. For å få kalt run()-metoden så må en ha en spesiell main-metode, hvor en først lager program-objektet med new og så ber dette program-objektet utfør run. Det er main()-metoden som kjøres når vi starter programmet med java-kommandoen i terminalvinduet eller bruker Eclipse sin Run-kommando. Les mer om forskjellen på hvordan kjøring av Python- og Java-programmer virker her: Kjøring av Python-programmer.

Oppgave

Del 1: Prøv først å få Java-programmet inn i kodingsprosjektet i Eclipse og test at det virker!

Del 2: Gjør om run()-metoden slik at den istedenfor å bruke en bestemt melding med message = "...", bruker en Scanner til å lese inn tekst fra brukeren.

Del 3: Lag en løkke slik at brukeren kan prøve med ulike meldinger inntil han/hun skriver inn "stopp". Hint: String-verdier bør sammenlignes med equals-metoden, ikke med ==

Del 4: Endre koden slik at secret-verdien settes lik lengden av teksten.

Del 5: Gjør om koden slik at også secret-verdien leses inn med Scanner-en.

 

  • No labels

1 Comment

  1. Unknown User (seljebu)

    For "versjon 2"

    @hal To fluer i en smekk: Idiomatic python og enklere sammenligning med java.

    if __name__ == "__main__":
    run()