Metoder

Motivering

När program blir större finns det behov att kunna strukturera det bättre. Rätt användning av metoder gör din kod mycket läsbar, är mindre felbenägen och lättare att sköta. Metoder hjälper att strukturera programmet på samma sätt som du bryter ett större probelm i mindre.

Du har redan använd metoder från första lektionen utan att vara medveten om. rect(x, y, bred, höjd) är en metod, QuestionInt() är en metod och många fler. Men även tidigare när du har använd tex sin(double) på din miniräknare. Det de har gemensam att alla dessa metoder har (i regel) ett enda syfte, en enda uppgift. Med hjälp av fyra värden rita ett antal pixlar på skärmen, Gör ett pop-up fönster med en fråga eller levererar ett värde som har ett visst matematiskt samband med vinkeln i en triangel.

Kodexempel 1

Vi inför egna metoder för att våra program liknar mer sättet hur vi tänker, hur vi angripa ett problem och att öka läsbarheten. I första steget ta vi ett program till ett problem vi hade förr: Stapeldiagram

import java.util.Random;
//Variabler

int[] tal = new int[20];  // skapa lådan (=fält) 'tal' med 20 fack
Random rnd = new Random();


  void setup(){
    size(620,600);
    int i = 0;
    while( i < tal.length ){
        int slmp = rnd.nextInt(200)+20; // generera slumptal 50 .... 450 och spara i slmp
        tal[i] = slmp;                  // och spara i slmp
        i++;
    }

    for(int j = 0; j < tal.length; j++){  //loopar genom fältet 
        int pos = 10+j*30; 
        rect(pos, 10, 20, tal[j] );    // och använda tal[i] för rektangelns höjd 
    }
  }

Med metoder kan det ser ut så här. Vi skapa två metoder (fyllFaltetMedSlumptal(), RitaAllaTalSomstaplar() ) lite längre ner, anropa de i huvudprogrammet (under lektioner visas hur det kan läggas i andra filer):

import java.util.Random;
  //Variabler
    int[] tal = new int[20];    

 // Huvudprogram
  void setup(){
    size(620,600);
    fyllFaltetMedSlumptal();
    RitaAllaTalSomstaplar(); 
  }

 //======= egna metoder ====================================

  void fyllFaltetMedSlumptal(){
    Random rnd = new Random();
    int i = 0;
    while( i < tal.length ){
    int slmp = rnd.nextInt(400)+50; // generera slumptal 50 .... 450 och spara i slmp
    tal[i] = slmp;            // och spara i slmp
    i++;
    }
  } // end fyllFaltetMedSlumptal

  void RitaAllaTalSomstaplar(){
    for(int j = 0; j < tal.length; j++){  //loopar genom fältet 
    int pos = 10+j*30; 
    rect(pos, 10, 20, tal[j] );    // och använda tal[i] för rektangelns höjd 
    }
  } // end RitaAllaTalSomstaplar

Läsbarheten i 'huvudprogrammet' är nu mycket bättre eftersom metodnamnen talar om för oss vad som är syfte med dem. Det visar också för den som läsa koden att problemet (Rita diagram med 20 slumptal) har delats upp i två mindre:

  1. Fyll fältet med innehåll
  2. Rita staplar beroende på fältet

Här används metoder på det enklaste sättet. Man sammanfattar kod med ett nytt namn och flytter den utanför. I exemplet har vi nu tre block setup, fyllFaltetMedSlumptal och RitaAllaTalSomstaplar. Först körs setup-blocket. I den anropas metoden fyllFaltetMedSlumptal. Programmet hoppar ner till rätt ställe och utför koden. Efter det är klar återvänder programmet till raden efter anropet och fortsätter, här med RitaAllaTalSomstaplar.

Syntax = skrivsätt

För att använda metoder krävs två saker: man måste deklarera metoden och sedan anropa. Man har flera sätt,vi börjar med det enklaste.

Deklaration:

Börja med void, sedan namnet följd av parentes. Det kallas för metodhuvud. Sedan kommer måsvingeparet. Mellan de sätts koden som ska utföras när metoden anropas. Det kallas metodkropp. Metoddeklaration från förra exemplet:

void fyllFaltetMedSlumptal(){
    Random rnd = new Random();
    int i = 0;
    while( i < tal.length ){
    int slmp = rnd.nextInt(200)+20; // generera slumptal 20 .... 220 och spara i slmp
    tal[i] = slmp;            // och spara i slmp
    i++;
    }
  } // end fyllFaltetMedSlumptal

Anrop

Anrop sker från andra programdelar genom att skriva namnet följd av parenteser. Metodanrop från förra exemplet:

 fyllFaltetMedSlumptal();

Än så har koden blivit mer läsbart. Men metoder är inte begränsad till ett enda anrop. Vi kunde ändra 'Huvudprogrammet' ändra så här:

// Huvudprogram
  void setup(){
    size(620,600);
    fyllFaltetMedSlumptal();
    RitaAllaTalSomstaplar(); 

    translate(0,600);  // flytta ner origo
    scale(1,-1); // vända om y-axel

    fyllFaltetMedSlumptal();
    RitaAllaTalSomstaplar(); 

  }

Metod med in-parameter

För att göra metoder mer flexibla kan man lägga till en eller flera in-parameter. Vi modfiera deklarationen. Jämför med förra version av fyllFaltetMedSlumptal:

void fyllFaltetMedSlumptal(int min, int max){        <--- Kolla! Nytt huvud 
    Random rnd = new Random();
    int i = 0;
    while( i < tal.length ){
    int slmp = rnd.nextInt(max-min)+min; // generera slumptal min .... max och spara i slmp
    tal[i] = slmp;            // och spara i slmp
    i++;
    }
  } // end fyllFaltetMedSlumptal

Men det innebär även en ändring i sättet att anropa metoden. I deklarationen skrivs void fyllFaltetMedSlumptal(int min, int max) Och då krävs det att metoden anropas med två int-värden:

// Huvudprogram
  void setup(){
    size(620,600);
    fyllFaltetMedSlumptal(20,800);  <-------- Nytt sätt !!!
    RitaAllaTalSomstaplar(); 
  }

Laboration 1

Gör en metod innebär att definera metoden OCH anropa det med ett liten exempelhuvudprogram!

Du kan börja så här:

// Huvudprogram
  void setup(){
    size(620,600);
    kvadrat(50,100,200);
  }

  // och här ska komma definitionen/deklarationen för kvadrat:

// Huvudprogram
  void setup(){
    size(620,600);
    ritaXYaxlar(300,400);  // 300,400 är origo för axlarna
  }

  // och här ska komma definitionen/deklarationen för ritaXYaxlar:

Gör en metod som rita en enkel bil ( typ: två-tre rektanglar, två cirklar) på valfritt ställe på skärmen. In-parameter är x, y, och sedan kanske till och med - startnummer och färg. Rita så på ett enkelt sätt flera bilar på skärmen.


Metoder med ut-värden

Än så länge beskriver vi metoder som har ingen, ett eller flera in-parameter. Inte sällan vill man ha något ut av en metod. Alltså att det till exempel beräknas något som sedan ges tillbaka. Här ett lite exempel från fysiken:


void setup() {
  size(600, 600);
  textSize(36);
  float temp = QuestionFloat("Temperatur i Celsius?"); 
  float fah = Celsius2Fahrenheit(temp);   <--- Anrop med ett värde
  text(temp + " C⁰", 50, 50);
  text(" blir " + fah + " F", 50, 100);
}


float Celsius2Fahrenheit(float celsius)    <--- Innehållet av temp kopieras till celsius
{
  float fahrenheit;
  fahrenheit = celsius * 1.8 + 32;

  return fahrenheit;
}

Observera två nyheter:

För att kunna få ett värde tillbaka måste vi specificera retur-värdets typ i det här fallet float. typen skrevs före metodnamnet. Det som returneras, här svar, måste då vara av typen double

Alla dessa varianter kan kombineras. Med eller utan returnvärde och inget, ett eller flera in-parameter. Det finns inga regler angående typer. Det kan vara vilken som helst in-typ och valfritt ut-typ:

void setup() {

   int tal = 1337;

boolean b = isItPrime(tal);

  if( b == true  ) {
        println(tal + " är ett primtal!");
        } else {
        println(tal + " är INGET primtal!");
        }
  }     

boolean isItPrime(int n) {

  boolean svar = true;
  for (int i = 2; i < n; i++) {
    if (n % i == 0) {
      svar = false;
    }
  }

  return svar;

}

Namngivning

Dessa regler gäller för namngivning av variabler och metoder:

- Skillnad mella stora och små bokstäver: getAntal, getantal, GETANTAL är tre olika variabler
- ett ord, så inte `antal elever` men `antal_elever` är OK.
- Tillåtna tecken: a - z, A-Z, 0 - 9, och _
- måste börja med bokstav eller _ 
- Good coding: Vi använder camelCase. variabelnamn börja men gemener, varje nytt ord `utan` mellanslag med versaler. Tex `antalElever, maxWidth, minBredd`
- I rekommendationer från Oracle ('Ägare' av Java) kan läsas: *Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized. Examples: run(); runFast(); getBackground();*

Laboration 2

Gör en metod innebär att definera metoden OCH anropa det med ett liten exempelhuvudprogram!

    float a = 3.142459,  b = 13.37; 

    float maximum = Max(a,b); 

    text("Störst: " + maximum, 100,500);

Nyckelord för metoder

Viktiga begrepp

  • metoddefinition: Hela koden som beskriver metoden

  • metodhuvud: första raden av metoddefinition.
    I den finns <returntyp> <metodnamn>(<typ> namn1, <typ> namn2, ...)

  • metodkropp: Själva koden för metoden.

  • signatur : <metodnamn>(<typ> namn1, <typ> namn2, ...) samma som metodhuvud men utan returntyp. Sä länge metoder har olika signaturer kan de har samma namn.

Metoder och fält som in-parameter

In-parametrar för metoder är inte begränsade till int, float, double eller sträng. Det kan vara vad som helst, även fält. Ett exempel för konsollfönstret:

void setup() {
  int[] f = {1, 2, 3, 4, 5};

  snyggUtskrift(f);

}

void snyggUtskrift(int[] arr) {
  for (int i = 0; i < arr.length; i++) {
    print(arr[i] + "\t");
  }
  println();
}


Ett fält kan vara likaså ett returvärde för en metod:


double[] multiplerAvPI(int a) {

  double[] arr = new double[a];
  for (int i = 0; i < a; i++) {
    arr[i] = (i+1) * PI;
  }
  return arr;
}

Laboration 3 - kopplar ihop fält och metoder

Metoder_Array.pdf

Hur skapas en metod?

du har en del av programmet som ska bli en metod. Med hjälp av dessa steg kan det översättas till en metod. Vi tar isItPrime från ovan som exempel. Först utan metod:

void setup() {

   int tal = QuestionInt("Vilket tal ska testas?");

boolean arPrimtal = true;
  for (int i = 2; i < tal; i++) {
    if (tal % i == 0) {
      arPrimtal = false;
    }
  }

  if( arPrimtal ) {
    text("Det är ett primtal", 20,100);
    } else {
    text("Det är INGET primtal", 20,100);
    }

}

    boolean arPrimtal = true;
  for (int i = 2; i < tal; i++) {
    if (tal % i == 0) {
      arPrimtal = false;
    }
  }
boolean testPrimtal(int tal){
    boolean arPrimtal = true;


    return arPrimtal; 
}
void setup() {

   int tal = QuestionInt("Vilket tal ska testas?");

boolean arPrimtal = testPrimtal( tal ); //anrop

  if( arPrimtal ) {
    text("Det är ett primtal", 20,100);
    } else {
    text("Det är INGET primtal", 20,100);
    }

}


// ===== metoddklaration ===================================
    boolean testPrimtal(int tal){
        boolean arPrimtal = true;
            for (int i = 2; i < tal; i++) {
                if (tal % i == 0) {
                arPrimtal = false;
            }
        }

        return arPrimtal; 
    }