Helsingin yliopisto / Tietojenkäsittelytieteen laitos
Copyright © 2008 Arto Wikla. Tämän oppimateriaalin käyttö on sallittu vain yksityishenkilöille opiskelutarkoituksissa. Materiaalin käyttö muihin tarkoituksiin, kuten kaupallisilla tai muilla kursseilla, on kielletty.

Javaa Scalalla 2
Scala-kielelle muokattuja esimerkkejä kurssimateriaalista Ohjelmoinnin perusteita Java-kielellä: luku 2

(Muutettu viimeksi 6.10.2008)

Tälle sivulle on koottu joukko Ohjelmoinnin perusteita Java-kielellä -kurssimateriaalini esimerkkejä Scala-kielellä ohjelmoituna. Koska esimerkit on muokattu suoraan Java-versioista, ne eivät missään nimessä edusta Scalan käyttöä tyylikkäimmillään! Tämän sivun esimerkkien rinnalla kannattaa katsella kyseistä Java-kurssimateriaalia. Kappalenumerointi ja -otsikointi ovat samat.

2. Algoritmien laatimisen alkeet: lausekkeita, lauseita, metodeita..., vähän olioitakin

2.1 Pieni ohjelma

Hoi maailma -sovellus

2.2 Tyyppejä, aritmeettisia lausekkeita ja sijoituksia

Esim.scala
var lkm=1
var kpl=100
var pituus=1.1
var leveys=2.2
var korkeus=3.3

lkm = kpl- 10 * (kpl-8)
pituus = leveys * korkeus + pituus * lkm

lkm = 5
korkeus = 5
kpl = lkm/2        // arvo on 2
leveys = korkeus/2 // arvo on 2.5

lkm = 17%3  // arvo on 2

Mesim.scala
val alku  = "kissa"
val loppu = "vie"
var koko = ""

koko = alku + loppu             // "kissavie"
koko = alku + " " + loppu       // "kissa vie"
koko = alku + " " + loppu +"!"  // "kissa vie!"

KateKoe.scala
val jono  = "kissa"
var tulos = ""

tulos = jono + 100
println(tulos)

tulos = jono + 100 + 1000  // !
println(tulos)

tulos = 100 + jono
println(tulos)

tulos = 100 + 1000 + jono  // !
println(tulos)

2.3 Kirjoittamista ja lukemista

Kaiuta.scala
val i = readLine
println(i)

Viisas.scala
println("Mikä on nimesi?")
val syottörivi = readLine
println("Mitä kokonaislukua ajattelet?")
val kokonaisluku = readInt
println("Mitä desimaalilukua ajattelet?")
val desimaaliluku = readDouble
print  ("Tiedän, että nimesi on "+syottörivi)
println(" ja että ajattelit lukuja " + 
        kokonaisluku+" ja "+ desimaaliluku+".")
println("Enkö olekin viisas!")

KolmeKarvo.scala
println("\n  **** Keskiarvo-ohjelma ****\n")

print("Anna 1. luku: ")
val luku1 = readDouble
print("Anna 2. luku: ")
val luku2 = readDouble
print("Anna 3. luku: ")
val luku3 = readDouble

val summa = luku1 + luku2 + luku3
val karvo = summa/3

println("Lukujen keskiarvo on " + karvo)

2.4 Loogisia lausekkeita, valintaa ja toistoa

Esimerkkejä toistolauseista (ForWhileDo.scala)
for (i <- 0 until 6) // arvot 0, ..., 5
  println(i)

for (i <- 0 to 5)    // myös arvot 0, ..., 5
  println(i)

for (i <- 0 to 2)
  for (j <- 0 to 1)
    println(i+"  "+j)

var i=0
while (i<6) {       // arvot 0, ..., 5
  println(i)
  i += 1
}

i=0  // määritelty jo edellä
do {
  println(i)        // arvot 0, ..., 5
  i += 1
} while (i<6)

Tuplatw.scala
println("Lukujen tuplausohjelma, nolla lopettaa")
var luku = readInt
while (luku != 0) {
  println("Tuplana: "+luku*2)
  luku = readInt
}
println("Siinä ne olivat.")

Pariton.scala
var luku = 0
var parillinen = false

do {
  println("Anna pariton luku!")
  luku = readInt
  parillinen = (luku%2 == 0);
  if (parillinen)
    println("Eihän "+luku+" ole pariton ...")
} while (parillinen)

println("Hienoa, "+luku+" on pariton!")


Karvo1.scala
var lukujenLkm = 0
var lkmOk = true

var luku = 0.0
var lukujenSumma = 0.0
var lukujenKarvo = 0.0

println("\n**** Keskiarvon laskenta ****\n");

// Monenko luvun keskiarvo lasketaan
// (tarkistetaan, että määrä ei ole negatiivinen):

do {
  print("Monenko luvun keskiarvo lasketaan? ");
  lukujenLkm = readInt
  lkmOk = (lukujenLkm >= 0)   // nollakin kelpaa!
  if (!lkmOk)
    println("Virhe: negatiivinen ei kelpaa!");
} while (!lkmOk);

// Lukujen summan laskenta:

for (monesko <- 1 to lukujenLkm) {
  print("Anna "+monesko+". luku: ");
  luku = readDouble;
  lukujenSumma += luku;
}

  // Keskiarvon tulostus (estetään 0:lla jakaminen):

if (lukujenLkm == 0)
  println("\nEi lukuja, ei keskiarvoa.\n");
else {
  lukujenKarvo = lukujenSumma/lukujenLkm;
  println("\nKeskiarvo on "+lukujenKarvo+".\n");
}


Karvo2.scala
var lukujenLkm = 0

var luku = 0.0
var lukujenSumma = 0.0
var lukujenKarvo = 0.0

println("\n**** Keskiarvon laskenta ****\n");

// Käyttöohjeen tulostus:

println("Syötä luvut, joiden keskiarvon haluat laskea!\n"+
        "Negatiivinen luku ilmoittaa lukujen loppuvan.\n")

// Lukujen summan laskenta:

luku = readDouble      // 1. luku (voi olla jo loppumerkki!)
while (luku >= 0) {
  lukujenSumma += luku
  lukujenLkm += 1
  luku = readDouble    // seuraava luku tai loppumerkki
}

  // Keskiarvon tulostus (estetään 0:lla jakaminen):

if (lukujenLkm == 0)
  println("\nEi lukuja, ei keskiarvoa.\n")
else {
  lukujenKarvo = lukujenSumma/lukujenLkm
  println("\nKeskiarvo on "+lukujenKarvo+".\n")
}


Karvo3.scala
var lukujenLkm = 0
var jatkuu = ""

var luku = 0.0
var lukujenSumma = 0.0
var lukujenKarvo = 0.0

println("\n**** Keskiarvon laskenta ****\n");

  // Lukujen summan laskenta:

do {
  println("Onko vielä lukuja? (kyllä/ei)");
  jatkuu = readLine
  if (jatkuu == "kyllä") {  // TOIMIIKS TÄÄ TOSIAAN???
     println("Anna " + (lukujenLkm + 1) + ". luku");
     luku = readDouble
     lukujenSumma += luku;
     lukujenLkm += 1;
  }
} while (jatkuu == "kyllä");

  // Keskiarvon tulostus (estetään 0:lla jakaminen):

if (lukujenLkm == 0)
  println("\nEi lukuja, ei keskiarvoa.\n")
else {
  lukujenKarvo = lukujenSumma/lukujenLkm
  println("\nKeskiarvo on "+lukujenKarvo+".\n")
}


Tarkista1.scala
println("Anna kokonaisluku.")
try {
  val luku = readInt
  println("Annoit luvun " + luku)
}
catch {
  case ex: Exception => println("Et syöttänyt kokonaislukua!")
}

Tarkista2.scala
var luku = 0
var kunnonLuku = false

do {
  println("Anna kokonaisluku.");
  try {
    val luku = readInt
    println("Annoit luvun " + luku)
    kunnonLuku = true
  }
  catch {
    case ex: Exception => {
      println("Et syöttänyt kokonaislukua!")
      println("Yritä uudelleen!")
    }
  }
} while (!kunnonLuku)

SuurinSyottoluku.scala
var syöttöluku = 0
var toistaiseksiSuurin = 0;  // muuttuu aina, jos on lukuja

println("************************************************\n" +
        "* Ohjelma syöttölukujen maksimiarvon etsintään *\n" +
        "*        Nolla päättää syötteet.               *\n" +
        "*        Anna luvut!                           *\n" +
        "************************************************\n");

syöttöluku = readInt
toistaiseksiSuurin = syöttöluku

while (syöttöluku != 0) {
  if (syöttöluku > toistaiseksiSuurin)
    toistaiseksiSuurin = syöttöluku
    syöttöluku = readInt
  }

if (toistaiseksiSuurin == 0)
  println("Ei lukuja!")
else
 println("Suurin luku oli " + toistaiseksiSuurin)


2.5. Metodeista

HipHoh.scala
def tulostaHip = println("Hip heijjaa!")

def tulostaHoh = println("Hoh hoijjaa!")

def tulostaSuperHip() {
  println("------------");
  tulostaHip
  tulostaHip
  tulostaHip
  println("------------")
}

println("Nyt se alkaa:")
tulostaHip
tulostaHoh
tulostaHip
tulostaHip
tulostaHoh
tulostaSuperHip
println("Tähän se loppui.")

TulostaHuudahdus.scala
def tulostaHuudahdus(viesti:String, kertaa:Int) = {
  for (i <- 1 to kertaa)
    println(viesti)
}

tulostaHuudahdus("Hip heijjaa!", 2)

KahdenKarvo.scala
def tulosta2Karvo(luku1:Double, luku2:Double) = 
  val summa = luku1 + luku2
  val karvo = summa/2
  println("Lukujen "+luku1+" ja "+luku2+ " keskiarvo on "+karvo+".")
}

tulosta2Karvo(1, 2)
tulosta2Karvo(-30.2, 1.2)
tulosta2Karvo(-1, 1)
tulosta2Karvo(3.14, 123.1)

KahdenKarvoFun.scala
def laske2Karvo(luku1:Double, luku2:Double) = {
  val summa = luku1 + luku2;
  val karvo = summa/2;
  karvo
}

var a = laske2Karvo(1, 2)
println(a)

a = laske2Karvo(-30.2, 1.2)
println(a);

println(laske2Karvo(-1, 1))
println(laske2Karvo(3.14, 123.1))

println(laske2Karvo(2, laske2Karvo(3,4)))

Itse.scala
def itseisArvo(luku:Int) = if (luku < 0) -luku else luku

var a = itseisArvo(3)
println(a)

a = itseisArvo(-34)
println(a)

println(itseisArvo(-2987))

Korostuksia.scala
def osoitteleJono(teksti:String) = "------> "+teksti+" <------"

var kissa = "Missu"
var s = ""

s = osoitteleJono(kissa)
println(s)

println(osoitteleJono("hiiohei"))

println(osoitteleJono("A")+osoitteleJono("B"))

println(osoitteleJono(osoitteleJono("AW")))

Tarkistus.scala
def oikeinko(i:Int) =  i>0 && i%2==0 && i!=274 && i!=666

var sluku = 0

do {
  println("Syötä kunnon luku!")
  sluku = readInt
} while (!oikeinko(sluku));

println("Vihdoin kunnon luku: "+sluku)

Nelio.scala
object Kirjasto {
  def tulostaNelio() = println("neliö")
  def tulostaNelio(luku:Int) = println(luku*luku)
  def tulostaNelio(luku:Double) = println(luku*luku)
  def tulostaNelio(i:Int, j:Int) =
    for (a <- 1 to i) {
      for (b <- 1 to j)
        print("*")
      println()
    }
}

Kirjasto.tulostaNelio()
Kirjasto.tulostaNelio(12)
Kirjasto.tulostaNelio(3.14)
Kirjasto.tulostaNelio(4, 6)

2.6 Luokista ja olioista

Kuulaskuritesti.scala
class Kuulaskuri {
  private var kuu=1   // sallitut arvot 1,..12
  // ----- aksessorit: -----------
  def moneskoKuu = kuu
  def seuraavaKuu {
    kuu += 1
    if (kuu == 13)
      kuu = 1
  }
}
//---------------------------------------------

var tämäKuu: Kuulaskuri = null
var tuoKuu = new Kuulaskuri

// käydään läpi 27 kuukautta:

println("Kaksikymmentäseitsemän kuukautta:");
  for (i <- 1 to 27) {
    print(tuoKuu.moneskoKuu + " ")
    tuoKuu.seuraavaKuu
  }

println()

// kopioidaan viite, ei oliota:

tämäKuu = tuoKuu

println("tuoKuun:n arvo on nyt "+tuoKuu.moneskoKuu)
println("tämäKuun:n arvo on nyt "+tämäKuu.moneskoKuu)

// edetään seuraavaan kuukauteen, myös tuoKuu etenee,
// koska muuttujat viittaavat SAMAAN olioon:

tämäKuu.seuraavaKuu

println("tuoKuun:n arvo on nyt "+tuoKuu.moneskoKuu)
println("tämäKuun:n arvo on nyt "+tämäKuu.moneskoKuu)

// luodaan kaksi uutta Kuulaskuri-oliota, vanhaan ei jää
// enää viitteitä, se jää roskienkerääjän hoideltavaksi:

tämäKuu = new Kuulaskuri
tuoKuu  = new Kuulaskuri

// edistetään tämäKuu:n osoittamaa oliota kahdesti:

tämäKuu.seuraavaKuu
tämäKuu.seuraavaKuu

// tulostetaan 15 peräkkäistä kuukauden numeroa MOLEMMISTA
// olioista:

println("Viisitoista kuukautta rinnakkain:")
for (i <- 1 to 15) {
  println(tämäKuu.moneskoKuu+"\t" + tuoKuu.moneskoKuu);
  tämäKuu.seuraavaKuu
  tuoKuu.seuraavaKuu
}


Pikkuvarastotesti.scala
class Pikkuvarasto (private var määrä: double, val tuote: String) {

  def this() = this(0.0, "(nimetön)")  // parametriton konstruktori oletusarvoin

  def paljonkoOn = määrä // aksessori on tehtävä koska määrä on private!

  def vieVarastoon(paljonko: double) = if (paljonko > 0) määrä += paljonko

  def otaVarastosta(paljonko: double) =
    if (paljonko <= 0)  0.0
    else if (paljonko <= määrä) {määrä -= paljonko;  paljonko;}
    else {val saatiin = määrä; määrä = 0; saatiin;}

  override def toString =  "("+tuote+": "+määrä+")"

  def summa(toinen: Pikkuvarasto) =
    new Pikkuvarasto(määrä + toinen.määrä, tuote + toinen.tuote);
}
//------ kokeilua ------------

val mehua =  new Pikkuvarasto(10, "Mehu")
val olutta = new Pikkuvarasto(123.4, "Olut")
val bensaa = new Pikkuvarasto(90.1, "Bensa")
println(mehua); println(olutta); println(bensaa)

val a = new Pikkuvarasto(); println(a)

val b = mehua; println("" + b + mehua)
b vieVarastoon(25); println("" + b + mehua)

println("Muuttuja bensaa:" + bensaa + ", määrä=" + bensaa.paljonkoOn +
        ", nimi=" + bensaa.tuote)

println(bensaa)
bensaa.vieVarastoon(27.4); println(bensaa)
bensaa.vieVarastoon(-34.1); println(bensaa)

println(olutta)
var saatiin: double  = olutta.otaVarastosta(10.2)
println("Saatiin " + saatiin + ", tilanne: "+olutta)
saatiin = olutta.otaVarastosta(-78.8)
println("Saatiin " + saatiin + ", tilanne: "+olutta)
saatiin = olutta.otaVarastosta(175.5)
println("Saatiin " + saatiin + ", tilanne: "+olutta)

olutta.vieVarastoon(432.1)
val c = mehua.summa(olutta)
println("" + mehua + olutta + c)

var d = c.summa(bensaa); println("" + c + bensaa + d)

d = d.summa(bensaa.summa(mehua)); println(d)


OlioArvonaEsim.scala
// Pikkuvaraston määritelmä kopioitu tännekin ...

def lueVarasto() = {
  println("Tuotteen nimi?")
  val nimi = readLine
  var sisalto = 0.0;
  do {
    println("Tuotteen määrä? (ei-negatiivinen)");
    sisalto = readDouble
  } while (sisalto < 0)
  new Pikkuvarasto(sisalto, nimi)  // HUOM: viite!
}

println("Luodaanpa varasto!")
val varasto = lueVarasto()
println("Varasto on: " + varasto)

2.7 String-olioita ja char-arvoja

JonoVertailu.scala
var vastaus = ""

do {
  print("Anna ensimmäinen merkkijono: ")
  val eka = readLine
  print("Anna toinen merkkijono     : ")
  val toka = readLine

  if (eka < toka)
    println("Esimmäinen on ennen toista.");
  else if (eka == toka)
    println("Jonot ovat samat.");
  else // eka > toka
    println("Toinen on ennen ensimmäistä.");

  println("\nHaluatko jatkaa? (enter jatkaa, kaikki muu lopettaa)");
    vastaus = readLine

} while (vastaus == "")

Kissako.scala
println("Syötä rivi. Etsin siltä kissaa.")
val syöttorivi = readLine
if (syöttorivi contains "kissa")
  println("Jossakin kohdassa syöttörivillä on kissa!")
else
  println("Rivi on kissaton.")

2.8 Taulukko-olioista

KaannaLuvut.scala
val luku = new Array[Int](10)

// luetaan 10 lukua:

for (i <- 0 until luku.length) {
  println("Anna luku "+(i+1))
  luku(i) = readInt
}

// tulostetaan luvut käänteisessä järjestyksessä:

println("Luvut lopusta alkuun:")
  for (i <- 0 until luku.length reverse)
    println(luku(i))


KaannaLuvut2.scala
var lukumäärä = 0
do {
  println("Montako lukua käännetään? (Vähintään yksi!)");
  lukumäärä = readInt
} while (lukumäärä < 1);

val luku = new Array[Int](lukumäärä) // Huom: luettu arvo!

// Loppuosa ohjelmasta säilyy aivan ennallaan!

for (i <- 0 until luku.length) {
  println("Anna luku "+(i+1))
  luku(i) = readInt
}

// tulostetaan luvut käänteisessä järjestyksessä:

println("Luvut lopusta alkuun:")
  for (i <- 0 until luku.length reverse)
    println(luku(i))


Matriisi7.scala
val matriisi = new Array[Array[Int]](2, 3)

for (rivi <- 0 until matriisi.length)
  for (sarake <- 0 until matriisi(rivi).length) {
     println("Anna alkio "+rivi+", "+sarake)
     matriisi(rivi)(sarake) = readInt
  }

// kerrotaan alkiot 7:llä:

for (rivi <- 0 until matriisi.length)
  for (sarake <- 0 until matriisi(rivi).length))
    matriisi(rivi)(sarake) *= 7;  // operaatio '*='kertoo!

// tulostetaan matriisi:

println("Seitsemällä kerrottuna:");

for (rivi <- 0 until matriisi.length) {
  for (sarake <- 0 until matriisi(rivi).length))
     print(matriisi(rivi)(sarake)+"\t")
  println()
}

// lasketaan alkioiden summa:

var summa = 0;
for (rivi <- matriisi)   // nyt tarvitaan vain alkioiden arvot!
  for (alkio <- rivi)
     summa = summa + alkio
println("Alkioiden summa on " + summa + ".")


Hae.scala
def hae(taulu: Array[Int], haettava:Int): Int = {
  for (i <- 0 until taulu.length)
    if (taulu(i) == haettava)
      return i // tärppäsi, lopetetaan samantien
  -1; // päästiin loppuun eikä löytynyt
}

// testipääohjelma
val a = new Array[Int](5)
a(0)=40; a(1)=20; a(2)=50; a(3)=10; a(4)=30

println(hae(a, 10))
println(hae(a, 20))
println(hae(a, 30))
println(hae(a, 40))
println(hae(a, 50))
println(hae(a, 60))


BinHae.scala
def binHae(taulu: Array[Int], haettava:Int): Int = {
  var vasen = 0
  var oikea = taulu.length-1
  var keski = 0

  while (vasen <= oikea) {
    keski = (vasen+oikea)/2

    if (haettava == taulu(keski))
      return keski     // löytyi ja lopetetaan!

    if (haettava < taulu(keski))
      oikea = keski-1
    else
      vasen = keski+1
  }
    -1  // hakualue tuli tyhjäksi eikä löytynyt
}

// testipääohjelma
val a = new Array[Int](5)
a(0)=10; a(1)=20; a(2)=30; a(3)=40; a(4)=50

println(binHae(a, 5))
println(binHae(a, 10))
println(binHae(a, 20))
println(binHae(a, 30))
println(binHae(a, 35))
println(binHae(a, 40))
println(binHae(a, 50))
println(binHae(a, 60))


VaihtoJarj.scala
def vaihtoJarjesta(taulu: Array[Int]) = {
  for (i <- 0 until taulu.length-1)
    for (j <- i+1 until taulu.length)
      if (taulu(i) > taulu(j)) { // onko järjestys väärä?
        val apu = taulu(i)
        taulu(i) = taulu(j)
        taulu(j) = apu
      }
}

// testipääohjelma
val a = new Array[Int](5)
a(0)=40; a(1)=20; a(2)=50; a(3)=10; a(4)=30

for (arvo <- a) print(arvo+" ")
println

vaihtoJarjesta(a)

for (arvo <- a) print(arvo+" ")
println


KuplaJarj.scala
def kuplaJarjesta(taulu: Array[Int]) = {
  for (i <- 1 to taulu.length reverse)
    for (j <- 0 until i-1)
      if (taulu(j) > taulu(j+1)) { // onko järjestys väärä?
        val apu = taulu(j)
        taulu(j) = taulu(j+1)
        taulu(j+1) = apu
    }
}

// testipääohjelma
val a = new Array[Int](5)
a(0)=40; a(1)=20; a(2)=50; a(3)=10; a(4)=30

for (arvo <- a) print(arvo+" ")
println

kuplaJarjesta(a)

for (arvo <- a) print(arvo+" ")
println


LisaysJarj.scala
def lisaysJarjesta(taulu: Array[Int]) = {
  for (i <- 1 until taulu.length) {
    val apu = taulu(i)
    var j = i
    while (j > 0 && taulu(j-1) > apu) {
      taulu(j) = taulu(j-1)
      j -= 1
    }
    taulu(j) = apu
  }
}

// testipääohjelma
val a = new Array[Int](5)
a(0)=40; a(1)=20; a(2)=50; a(3)=10; a(4)=30

for (arvo <- a) print(arvo+" ")
println

lisaysJarjesta(a)

for (arvo <- a) print(arvo+" ")
println


STauluKoe.scala


AlaspainLaskureita.scala
class AlaspainLaskureita(kpl:Int) {

  // tietorakenne ja konstruointi:

  private val laskurit: Array[Int] =
    if (kpl<=1)
      new Array[Int](1)
    else
      new Array[Int](kpl)
  for (i <- 0 until laskurit.length)
    laskurit(i) = 100

  def seuraava(n:Int):Int = {
    if (n<0 || n>=laskurit.length)
      return -1
    val arvo = laskurit(n)
    if (laskurit(n)>0)
      laskurit(n) -= 1
    return arvo
  }
}

// testiohjelma:

val a = new AlaspainLaskureita(10)
val b = new AlaspainLaskureita(-10)

// vähentyminen:
println(a.seuraava(3))
println(a.seuraava(3))
println(a.seuraava(3))

// virheellinen alkio:
println(a.seuraava(12))

// loppuuko väheneminen:
for (i <- 0 until 98)
  a.seuraava(7)

println(a.seuraava(7))
println(a.seuraava(7))
println(a.seuraava(7))
println(a.seuraava(7))

// tuliko yhden mittaiseksi väärästä konstruoinnista:
println(b.seuraava(0))
println(b.seuraava(0))
println(b.seuraava(1))


Takaisin sisältösivulle
Visitor Counter by Digits
(by WebCounter) (alkoi 6.5.2008)