Esempi di codice Scala e Java in cui il codice Scala sembra più semplice / ha meno righe?


94

Ho bisogno di alcuni esempi di codice (e sono anche molto curioso di loro) di codice Scala e Java che dimostrano che il codice Scala è più semplice e conciso del codice scritto in Java (ovviamente entrambi gli esempi dovrebbero risolvere lo stesso problema).

Se c'è solo un campione Scala con commenti come "questa è una fabbrica astratta in Scala, in Java sembrerà molto più ingombrante", allora anche questo è accettabile.

Grazie!

Mi piace più di tutto accettato e questo risponde


3
Con un po 'di lavoro sulle gambe, potresti trovare molti campioni su rosettacode.org
nicerobot

4
Come può esserci una risposta corretta in questo tipo di domanda?
lubrificanti poligenici

@polygenelubricants: e cosa suggerisci?
Roman

10
@Roman: Ci aspettiamo che Scala sia più conciso. Sarebbe più interessante se si potesse trovare qualcosa che fosse espresso in modo più conciso in Java che in Scala.
Randall Schulz

1
@Randall Schulz: tutti sanno che Scala è più conciso, ma a volte, a scopo accademico, abbiamo bisogno di una dimostrazione con esempi e teoria di fondo.
Roman

Risposte:


76

Miglioriamo l'esempio di stacker e utilizzare di Scala classi case :

case class Person(firstName: String, lastName: String)

La classe Scala sopra contiene tutte le funzionalità della classe Java sottostante e altre ancora , ad esempio supporta il pattern matching (che Java non ha). Scala 2.8 aggiunge argomenti denominati e predefiniti, che vengono utilizzati per generare un metodo di copia per le classi case, che fornisce la stessa capacità dei metodi with * della seguente classe Java.

public class Person implements Serializable {
    private final String firstName;
    private final String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public Person withFirstName(String firstName) {
        return new Person(firstName, lastName);
    }

    public Person withLastName(String lastName) {
        return new Person(firstName, lastName);
    }

    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Person person = (Person) o;
        if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) {
            return false;
        }
        if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) {
            return false;
        }
        return true;
    }

    public int hashCode() {
        int result = firstName != null ? firstName.hashCode() : 0;
        result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
        return result;
    }

    public String toString() {
        return "Person(" + firstName + "," + lastName + ")";
    }
}

Quindi, nell'uso abbiamo (ovviamente):

Person mr = new Person("Bob", "Dobbelina");
Person miss = new Person("Roberta", "MacSweeney");
Person mrs = miss.withLastName(mr.getLastName());

Contro

val mr = Person("Bob", "Dobbelina")
val miss = Person("Roberta", "MacSweeney")
val mrs = miss copy (lastName = mr.lastName)

2
In 2.7.xe 2.8.0 l'unica boxe è dentro productElementse unapply, non nel costruttore, campo o accessorio: gist.github.com/424375
retronym

2
Incoraggia tutti i tipi di cattiveria getter / setter. I setter dovrebbero essere aggiunti solo con estrema riluttanza, i getter dovrebbero essere aggiunti solo se necessario. Buon esempio di come l'aggiunta di "Semplicità" porti a cattive abitudini.
Bill K

7
@ Bill K: OK, allora avremo E case class Person(val firstName: String, val lastName: String) allora? Fare che cosa privata sarebbe possibile anche, ma non ha alcun senso, a causa della unapply ecc
soc

1
@shiva case class Person(private val firstName: String), ma allora non dovresti usare le classi case. Invece fare class Person(firstName: String)ed firstNameè privato per impostazione predefinita.
nilskp

1
@shiva No. La differenza tra vale private valè che i metodi di accesso, ovvero firstName()e firstName(String), sono pubblici o privati. In Scala i campi sono sempre privati. Affinché Scala generi metodi get / set in stile Java (oltre alle funzioni di accesso in stile Scala), c'è l' @BeanPropertyannotazione.
Esko Luontola

45

Ho trovato questo impressionante

Giava

public class Person {
    private final String firstName;
    private final String lastName;
    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    public String getFirstName() {
        return firstName;
    }
    public String getLastName() {
        return lastName;
    }
}

Scala

class Person(val firstName: String, val lastName: String)

Oltre a questi (scusate per non incollare, non volevo rubare il codice)


Questo codice scala non genererà getFirstNamee getLastNamemetodi. Devi annotare i parametri con scala.reflect.BeanPropertyannotazione per farlo.
Abhinav Sarkar

7
@ abhin4v: Sì, ma la convenzione del codice in Scala è di non avere funzioni di accesso con prefisso get. Il codice Java idiomatico è diverso dal codice Scala idiomatico. A volte il isprefisso utilizzato per i booleani. davetron5000.github.com/scala-style/naming_conventions/methods/…
Esko Luontola

6
Potresti farlo a case classe ottenere il toString, equalse hashCodegratuitamente (e non devi nemmeno rendere valesplicitamente gli argomenti ):case class Person(firstName: String, lastName: String)
Jesper

@shiva, per case class, non solo class.
nilskp

23

Attività: scrivi un programma per indicizzare un elenco di parole chiave (come i libri).

Spiegazione:

  • Input: List <String>
  • Output: Map <Character, List <String>>
  • La chiave della mappa va dalla "A" alla "Z"
  • Ogni elenco nella mappa viene ordinato.

Giava:

import java.util.*;

class Main {
  public static void main(String[] args) {
    List<String> keywords = Arrays.asList("Apple", "Ananas", "Mango", "Banana", "Beer"); 
    Map<Character, List<String>> result = new HashMap<Character, List<String>>(); 
    for(String k : keywords) {   
      char firstChar = k.charAt(0);     
      if(!result.containsKey(firstChar)) {     
        result.put(firstChar, new  ArrayList<String>());   
      }     
      result.get(firstChar).add(k); 
    } 
    for(List<String> list : result.values()) {   
      Collections.sort(list); 
    }
    System.out.println(result);         
  }
}

Scala:

object Main extends App {
  val keywords = List("Apple", "Ananas", "Mango", "Banana", "Beer")
  val result = keywords.sorted.groupBy(_.head)
  println(result)
}

È possibile utilizzare v.sorted invece di (v sortBy identity).
Eastsun

1
E con Scala 2.8, puoi usare mapValues ​​(_.sorted) invece di map {case ...}
Alex Boisvert,

10
Con Java 8, il codice è quasi identico a Scalas: keywords.stream (). Sort (). Collect (Collectors.groupingBy (it -> it.charAt (0))); fa il trucco!
Il coordinatore

11

Compito:

Hai un elenco peopledi oggetti della classe Personche ha campi namee age. Il tuo compito è ordinare questo elenco prima per namee poi per age.

Java 7:

Collections.sort(people, new Comparator<Person>() {
  public int compare(Person a, Person b) {
    return a.getName().compare(b.getName());
  }
});
Collections.sort(people, new Comparator<Person>() {
  public int compare(Person a, Person b) {
    return Integer.valueOf(a.getAge()).compare(b.getAge());
  }
});

Scala:

val sortedPeople = people.sortBy(p => (p.name, p.age))

Aggiornare

Da quando ho scritto questa risposta, ci sono stati dei progressi. I lambda (e i riferimenti ai metodi) sono finalmente atterrati in Java e stanno conquistando il mondo di Java.

Ecco come apparirà il codice sopra con Java 8 (contributo di @fredoverflow):

people.sort(Comparator.comparing(Person::getName).thenComparing(Person::getAge));

Sebbene questo codice sia quasi altrettanto breve, non funziona in modo così elegante come quello Scala.

Nella soluzione Scala, il Seq[A]#sortBymetodo accetta una funzione in A => Bcui Bè richiesto di avere un'estensione Ordering. Orderingè una classe di tipo. Pensa meglio di entrambi i mondi: come Comparable, è implicito per il tipo in questione, ma come Comparator, è estensibile e può essere aggiunto in modo retrospettivo ai tipi che non lo avevano. Poiché Java manca di classi di tipo, deve duplicare ogni metodo di questo tipo, una volta per Comparable, poi per Comparator. Ad esempio, vedi comparinge thenComparing qui .

Le classi di tipo consentono di scrivere regole come "Se A ha un ordine e B ha un ordine, anche la loro tupla (A, B) ha un ordine". Nel codice, ovvero:

implicit def pairOrdering[A : Ordering, B : Ordering]: Ordering[(A, B)] = // impl

È così che sortBynel nostro codice si possono confrontare per nome e poi per età. Quelle semantiche saranno codificate con la "regola" di cui sopra. Un programmatore Scala si aspetterebbe intuitivamente che funzioni in questo modo. Non è comparingstato necessario aggiungere metodi per scopi speciali come Ordering.

Lambda e riferimenti ai metodi sono solo la punta di un iceberg che è la programmazione funzionale. :)


La mancanza di lambda (o almeno riferimenti al metodo) è la caratteristica più importante che mi manca in Java.
Petr Gladkikh

@fredoverflow Grazie per aver aggiunto l'esempio di Java 8. Dimostra ancora perché l'approccio di Scala è superiore. Aggiungerò altro più tardi.
missingfaktor

@rakemous, amico, la risposta è stata scritta più di sei anni fa.
missingfaktor

10

Compito:

Hai un file XML "company.xml" che assomiglia a questo:

<?xml version="1.0"?>
<company>
    <employee>
        <firstname>Tom</firstname>
        <lastname>Cruise</lastname>
    </employee>
    <employee>
        <firstname>Paul</firstname>
        <lastname>Enderson</lastname>
    </employee>
    <employee>
        <firstname>George</firstname>
        <lastname>Bush</lastname>
    </employee>
</company>

Devi leggere questo file e stampare i campi firstNamee lastNamedi tutti i dipendenti.


Java: [tratto da qui ]

import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XmlReader {
  public static void main(String[] args) {   
    try {
      File file = new File("company.xml");
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
      DocumentBuilder db = dbf.newDocumentBuilder();
      Document doc = db.parse(file);
      doc.getDocumentElement().normalize();
      NodeList nodeLst = doc.getElementsByTagName("employee");
      for (int s = 0; s < nodeLst.getLength(); s++) {  
        Node fstNode = nodeLst.item(s); 
        if (fstNode.getNodeType() == Node.ELEMENT_NODE) {         
          Element fstElmnt = (Element) fstNode;
          NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("firstname");
          Element fstNmElmnt = (Element) fstNmElmntLst.item(0);
          NodeList fstNm = fstNmElmnt.getChildNodes();
          System.out.println("First Name: "  + ((Node) fstNm.item(0)).getNodeValue());
          NodeList lstNmElmntLst = fstElmnt.getElementsByTagName("lastname");
          Element lstNmElmnt = (Element) lstNmElmntLst.item(0);
          NodeList lstNm = lstNmElmnt.getChildNodes();
          System.out.println("Last Name: " + ((Node) lstNm.item(0)).getNodeValue());
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}



Scala: [tratto da qui , diapositiva # 19]

import xml.XML

object XmlReader {
  def main(args: Array[String]): Unit = {
    XML.loadFile("company.xml") match {
      case <employee> { employees @ _* } </employee> => {
        for(e <- employees) {
          println("First Name: " + (e \ "firstname").text)
          println("Last Name: " + (e \ "lastname").text)
        } 
      }
    }
  }
}

[EDIT di Bill; Controlla i commenti per la discussione] -

Hmm, come farlo senza rispondere in una sezione di risposta non formattata ... Hmph. Immagino che modificherò la tua risposta e ti permetterò di eliminarla se ti disturba.

Ecco come lo farei in Java con librerie migliori:

public scanForEmployees(String filename) {
    GoodXMLLib source=new GoodXMLLib(filename);
    while( String[] employee: source.scanFor("employee", "firstname", "lastname") )
    {
          System.out.println("First Name: " + employee[0]);
          System.out.println("Last Name: " + employee[1]);
    }
} 

Questo è solo un rapido trucco che non coinvolge la magia e tutti i componenti riutilizzabili. Se volessi aggiungere un po 'di magia, potrei fare qualcosa di meglio che restituire un array di array di stringhe, ma anche se questo GoodXMLLib sarebbe completamente riutilizzabile. Il primo parametro di scanFor è la sezione, tutti i parametri futuri sarebbero gli elementi da trovare che sono limitati, ma l'interfaccia potrebbe essere leggermente potenziata per aggiungere più livelli di corrispondenza senza problemi reali.

Ammetto che Java ha un supporto per le librerie piuttosto scarso in generale, ma dai - confrontare un uso orribile della vecchia libreria XML decennale (?) Di Java con un'implementazione basata sull'essere conciso non è giusto - ed è lontano da un confronto delle lingue!


hmm, l'esempio Java sarebbe più breve e più bello con un parser SAX o StAX. Ma ancora quello SCALA è davvero bello
oluies

5
Il codice Java è scritto esattamente per analizzare quel particolare file XML senza alcun tentativo di riutilizzo e molto codice duplicato. Chiunque l'abbia scritto stava cercando di dare l'impressione di non capire la codifica o di non capire la codifica.
Bill K

@ Bill K: non ho mai eseguito l'analisi XML in Java, quindi ho scelto questo esempio da un sito casuale. Sentiti libero di modificare la parte Java della risposta, non mi dispiace.
missingfaktor

Bene, supponiamo che tu stia parlando di differenze di lingua e non di differenze di libreria - in tal caso, le due sarebbero quasi identiche. L'unica differenza linguistica nel secondo esempio è la funzione match / case che potrebbe essere eseguita in una singola riga come ciclo for se implementata in questo modo dalla libreria.
Bill K

@ Bill K: No, ti sbagli completamente. Ci sono due funzionalità Scala molto potenti al lavoro qui: 1. Letterali XML 2. Pattern Matching. Java non ha nessuno di questi. Quindi il codice Java equivalente scritto in qualche ipotetica libreria NON sarà sicuramente identico. (Prova a scrivere, lo saprai.)
missingfaktor

10

Una mappa di azioni da eseguire in base a una stringa.

Java 7:

// strategy pattern = syntactic cruft resulting from lack of closures
public interface Todo {   
  public void perform();
}

final Map<String, Todo> todos = new HashMap<String,Todo>();
todos.put("hi", new Todo() { 
    public void perform() { 
        System.out.println("Good morning!");
    } 
} );

final Todo todo = todos.get("hi");
if (todo != null)
    todo.perform();
else
    System.out.println("task not found");

Scala:

val todos = Map( "hi" -> { () => println("Good morning!") } )
val defaultFun = () => println("task not found")
todos.getOrElse("hi", defaultFun).apply()

Ed è tutto fatto nel miglior gusto possibile!

Java 8:

Map<String, Runnable> todos = new HashMap<>();
todos.put("hi", () -> System.out.println("Good morning!"));
Runnable defaultFun = () -> System.out.println("task not found");
todos.getOrDefault("hi", defaultFun).run();

@Rahul G, penso che la tua modifica non sia corretta. todos.get("hi")restituisce Option[()=>Unit]che è necessario per abbinare correttamente.
huynhjl

@huynhjl, colpa mia. L'ho riavvolto.
missingfaktor

3
Può essere anche più breve:val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
Geoff Reedy

2
Ancora più breve: val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }e poitodos("hi")()
Martin Ring

8

Sto scrivendo un gioco di blackjack in Scala adesso. Ecco come apparirebbe il mio metodo dealerWins in Java:

boolean dealerWins() {
    for(Player player : players)
        if (player.beats(dealer))
            return false;
    return true;
}

Ecco come appare in Scala:

def dealerWins = !(players.exists(_.beats(dealer)))

Evviva le funzioni di ordine superiore!

Soluzione Java 8:

boolean dealerWins() {
    return players.stream().noneMatch(player -> player.beats(dealer));
}

scala ha una sintassi molto difficile.
ho

Scala è come i CSS, per molti attributi e proprietà da ricordare
AZ_

1
meglio:def dealerWins = !(players exists (_ beats dealer))
Kevin Wright

7

Mi è piaciuto questo semplice esempio di ordinamento e trasformazione, tratto dal libro "Beginning Scala" di David Pollak:

In Scala:

def validByAge(in: List[Person]) = in.filter(_.valid).sortBy(_.age).map(_.first)
case class Person(val first: String, val last: String, val age: Int) {def valid: Boolean = age > 18}
validByAge(List(Person("John", "Valid", 32), Person("John", "Invalid", 17), Person("OtherJohn", "Valid", 19)))

In Java:

public static List<String> validByAge(List<Person> in) {
   List<Person> people = new ArrayList<Person>();
   for (Person p: in) {
     if (p.valid()) people.add(p);
   }
   Collections.sort(people, new Comparator<Person>() {
      public int compare(Person a, Person b) {
        return a.age() - b.age();
      } 
   } );
   List<String> ret = new ArrayList<String>();
     for (Person p: people) {
       ret.add(p.first);
     }
   return ret;
}

public class Person {
    private final String firstName;
    private final String lastName;
    private final Integer age;
    public Person(String firstName, String lastName, Integer age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    public String getFirst() {
        return firstName;
    }
    public String getLast() {
        return lastName;
    }
    public Integer getAge() {
       return age;
    }
    public Boolean valid() {
       return age > 18;
    }
}

List<Person> input = new ArrayList<Person>();
input.add(new Person("John", "Valid", 32));
input.add(new Person("John", "InValid", 17));
input.add(new Person("OtherJohn", "Valid", 19));

List<Person> output = validByAge(input)

6

Che ne dici di Quicksort?


Giava

Quello che segue è un esempio Java trovato tramite una ricerca su Google,

l'URL è http://www.mycstutorials.com/articles/sorting/quicksort

public void quickSort(int array[]) 
// pre: array is full, all elements are non-null integers
// post: the array is sorted in ascending order
{
   quickSort(array, 0, array.length - 1);   // quicksort all the elements in the array
}


public void quickSort(int array[], int start, int end)
{
   int i = start;      // index of left-to-right scan
   int k = end;        // index of right-to-left scan

   if (end - start >= 1)               // check that there are at least two elements to sort
   {
       int pivot = array[start];       // set the pivot as the first element in the partition

       while (k > i)                   // while the scan indices from left and right have not met,
       {
           while (array[i] <= pivot && i <= end && k > i) // from the left, look for the first
              i++;                                        // element greater than the pivot
           while (array[k] > pivot && k >= start && k >= i) // from the right, look for the first
              k--;                                          // element not greater than the pivot
           if (k > i)                  // if the left seekindex is still smaller than
               swap(array, i, k);      // the right index, swap the corresponding elements
       }
       swap(array, start, k);          // after the indices have crossed, swap the last element in
                                       // the left partition with the pivot 
       quickSort(array, start, k - 1); // quicksort the left partition
       quickSort(array, k + 1, end);   // quicksort the right partition
    }
    else // if there is only one element in the partition, do not do any sorting
    {
        return;                        // the array is sorted, so exit
    }
}

public void swap(int array[], int index1, int index2) 
// pre: array is full and index1, index2 < array.length
// post: the values at indices 1 and 2 have been swapped
{
   int temp      = array[index1];      // store the first value in a temp
   array[index1] = array[index2];      // copy the value of the second into the first
   array[index2] = temp;               // copy the value of the temp into the second
}

Scala

Un rapido tentativo di una versione Scala. Stagione aperta per i miglioratori di codice; @)

def qsort(l: List[Int]): List[Int] = {
  l match {
    case Nil         => Nil
    case pivot::tail => qsort(tail.filter(_ < pivot)) ::: pivot :: qsort(tail.filter(_ >= pivot))
  }
}

1
Quel quicksort nelle liste collegate ha una complessità temporale O (n ^ 2) o no? Di solito per gli elenchi collegati viene utilizzato mergesort o simili.
Esko Luontola

3
Inoltre non è ricorsivo di coda e quindi inadatto come algoritmo performante (o uno che non sovraccaricherà lo stack)
oxbow_lakes

Grazie per i commenti utili. Avevo visto quicksort scritto da qualche parte in questo modo e sono rimasto colpito dalla sua compattezza, chiaramente non gli ho dato molta considerazione. Mi sono lasciato trasportare dal confronto LOC, che è sempre una cosa seducente con Scala v Java.
Don Mackenzie

2
Quicksort non è O (n ^ 2) negli elenchi funzionali, ma certamente presenta questo pericolo. Asintoticamente, è ancora nella media O (n log n) , ma c'è una maggiore probabilità statistica di colpire il caso peggiore O (n ^ 2) perché selezioniamo sempre il punto pivot in cima alla lista, piuttosto che sceglierne uno a caso .
Daniel Spiewak

Filtrare due volte è dannoso. Vedi nella mia risposta alla tua domanda l'uso di partitionper evitarlo.
Daniel C. Sobral

6

Mi è piaciuta così tanto la risposta di utente sconosciuto che cercherò di migliorarla. Il codice seguente non è una traduzione diretta dell'esempio Java, ma esegue la stessa operazione con la stessa API.

def wordCount (sc: Scanner, delimiter: String) = {
  val it = new Iterator[String] {
    def next = sc.nextLine()
    def hasNext = sc.hasNextLine()
  }
  val words = it flatMap (_ split delimiter iterator)
  words.toTraversable groupBy identity mapValues (_.size)
}

Ormai non ho installato scala-2.8, per testare questo frammento, ma immagino di poter vedere cos'è intendet - solo le "parole chiave" non vengono utilizzate affatto. Produce una mappa di tutte le corde e delle loro frequenze, no?
utente sconosciuto

@user Sì, è quello che fa. Non è questo ciò che viene realizzato dal tuo codice? Oh, capisco. Ho copiato la riga sbagliata. Lo aggiusterò adesso. :-)
Daniel C. Sobral

6

Mi piace molto il metodo getOrElseUpdate, trovato in mutableMap e mostrato qui, prima Java, senza:

public static Map <String, Integer> wordCount (Scanner sc, String delimiters) {
    Map <String, Integer> dict = new HashMap <String, Integer> ();
            while (sc.hasNextLine ()) {
                    String[] words = sc.nextLine ().split (delimiters);
                    for (String word: words) {
                        if (dict.containsKey (word)) {
                            int count = dict.get (word);
                            dict.put (word, count + 1);
                        } else
                            dict.put (word, 1);
                    }
            }       
    return dict;
}

sì - un WordCount, e qui in scala:

def wordCount (sc: Scanner, delimiter: String) = {
        val dict = new scala.collection.mutable.HashMap [String, Int]()
        while (sc.hasNextLine ()) {
                val words = sc.nextLine.split (delimiter)
                words.foreach (word =>
                      dict.update (word, dict.getOrElseUpdate (word, 0) + 1))
        }
        dict
}

Ed eccolo in Java 8:

public static Map<String, Integer> wordCount(Scanner sc, String delimiters)
{
    Map<String, Integer> dict = new HashMap<>();
    while (sc.hasNextLine())
    {
        String[] words = sc.nextLine().split(delimiters);
        Stream.of(words).forEach(word -> dict.merge(word, 1, Integer::sum));
    }
    return dict;
}

E se vuoi essere funzionale al 100%:

import static java.util.function.Function.identity;
import static java.util.stream.Collectors.*;

public static Map<String, Long> wordCount(Scanner sc, String delimiters)
{
    Stream<String> stream = stream(sc.useDelimiter(delimiters));
    return stream.collect(groupingBy(identity(), counting()));
}

public static <T> Stream<T> stream(Iterator<T> iterator)
{
    Spliterator<T> spliterator = Spliterators.spliteratorUnknownSize(iterator, 0);
    return StreamSupport.stream(spliterator, false);
}

filtere sortsono già stati mostrati, ma guarda come si integrano facilmente con la mappa:

    def filterKeywords (sc: Scanner, keywords: List[String]) = {
            val dict = wordCount (sc, "[^A-Za-z]")
            dict.filter (e => keywords.contains (e._1)).toList . sort (_._2 < _._2)
    } 

Mi piace molto questo esempio. Evita la facile via di confrontare le classi case e non commette l'errore di mostrare il codice Scala e non l'equivalente Java.
Daniel C. Sobral

5

Questo è un esempio molto semplice: Square integer e poi aggiungili


    public int sumSquare(int[] list) {
        int s = 0;
        for(int i = 0; i < list.length; i++) {
            s += list[i] * list[i]; 
        }
        return s;
    }

In scala:


val ar = Array(1,2,3)
def square(x:Int) = x * x
def add(s:Int,i:Int) = s+i

ar.map(square).foldLeft(0)(add)

La mappa compatta applica la funzione a tutti gli elementi dell'array, quindi:

Array(1,2,3).map(square)
Array[Int] = Array(1, 4, 9)

La piega a sinistra inizierà con 0 come accumulatore (i) e si applicherà add(s,i)a tutti gli elementi (i) dell'array, in modo che:

 Array(1,4,9).foldLeft(0)(add)  // return 14 form 0 + 1 + 4 + 9

Ora questo può essere ulteriormente compattato per:

Array(1,2,3).map(x => x * x ).foldLeft(0)((s,i) => s + i )

Questo non lo proverò in Java (per molto lavoro), trasforma XML in una mappa:


<a>
   <b id="a10">Scala</b>
   <b id="b20">rules</b>
</a>

Un altro liner per ottenere la mappa dall'XML:


val xml = <a><b id="a10">Scala</b><b id="b20">rules</b></a>

val map = xml.child.map( n => (n \ "@id").text -> n.child.text).toMap
// Just to dump it.
for( (k,v) <- map) println(k + " --> " + v)

Il problema con il tuo sumSquarein Scala è che sembra molto criptico a uno sviluppatore Java, che darà loro munizioni contro di te per lamentarsi che Scala è oscuro e complicato ...
Jesper

Ho riformattato un po 'per migliorare l'esempio. Spero che questo non faccia male a Scala.
Thomas

5
scala> da 1 a 10 map (x => x * x) sum res0: Int = 385 Vediamo che lo sviluppatore Java lo chiama criptico. A quel punto le dita nelle orecchie dicono nah-nah-nah.
psp

3
@Jesper Per uno sviluppatore non Java, Java sembra una grande quantità di boilerplate e rumore di linea. Ciò non significa che non puoi portare a termine un vero lavoro nella lingua.
James Moore

È possibile utilizzare reduceLeft (add) invece di foldLeft (0) (add). Penso che sia più facile da leggere quando il tuo elemento di partenza è l'elemento zero / identità del gruppo.
Debilski

5

Problema: è necessario progettare un metodo che eseguirà un dato codice in modo asincrono.

Soluzione in Java :

/**
* This method fires runnables asynchronously
*/
void execAsync(Runnable runnable){
    Executor executor = new Executor() {
        public void execute(Runnable r) {
            new Thread(r).start();
        }
    };
    executor.execute(runnable);
}

...

execAsync(new Runnable() {
            public void run() {
                ...   // put here the code, that need to be executed asynchronously
            }
});

La stessa cosa in Scala (usando gli attori):

def execAsync(body: => Unit): Unit = {
  case object ExecAsync    
  actor {
    start; this ! ExecAsync
    loop {
      react {           
        case ExecAsync => body; stop
      }
    }
  }    
}

...

execAsync{  // expressive syntax - don't need to create anonymous classes
  ...  // put here the code, that need to be executed asynchronously    
}

6
A partire da 2.8, questo può essere scritto come Futures.future {corpo} ed è in realtà più potente poiché il futuro restituito da questo può essere unito per ottenere il valore che alla fine valuta.
Dave Griffith,

3

Lo schema Circuit Breaker di Release It in FaKods di Michael Nygard ( collegamento al codice )

l'implementazione è simile a questa in Scala:

. . .
addCircuitBreaker("test", CircuitBreakerConfiguration(100,10))
. . .


class Test extends UsingCircuitBreaker {
  def myMethodWorkingFine = {
    withCircuitBreaker("test") {
      . . .
    }
  }

  def myMethodDoingWrong = {
    withCircuitBreaker("test") {
      require(false,"FUBAR!!!")
    }
  }
}

Che penso sia super carino. Sembra solo un pezzo del linguaggio, ma è un semplice mixin nell'oggetto CircuitBreaker che fa tutto il lavoro.

/**
 * Basic MixIn for using CircuitBreaker Scope method
 *
 * @author Christopher Schmidt
 */
trait UsingCircuitBreaker {
  def withCircuitBreaker[T](name: String)(f: => T): T = {
    CircuitBreaker(name).invoke(f)
  }
}

Riferimento in altre lingue Google per "Circuit breaker" + la tua lingua.


3

Sto preparando un documento che fornisce diversi esempi di codice Java e Scala, utilizzando solo le caratteristiche di semplice comprensione di Scala:

Scala: un Java migliore

Se desideri che aggiunga qualcosa, rispondi nei commenti.


Il titolo "Scala: A better Java" è fuorviante
Duckhunt

2

Perché nessuno lo ha pubblicato prima:

Giava:

class Hello {
     public static void main( String [] args ) {
          System.out.println("Hello world");
     }
}

116 caratteri.

Scala:

object Hello extends App {
     println("Hello world")
}

56 caratteri.


1
Applicationtratto considerato dannoso ... scala-blogs.org/2008/07/…
missingfaktor

1

I flussi infiniti valutati pigramente sono un buon esempio:

object Main extends Application {

   def from(n: Int): Stream[Int] = Stream.cons(n, from(n + 1))

   def sieve(s: Stream[Int]): Stream[Int] =
     Stream.cons(s.head, sieve(s.tail filter { _ % s.head != 0 }))

   def primes = sieve(from(2))

   primes take 10 print

}

Ecco una domanda che si rivolge a flussi infiniti in Java: un iteratore infinito è un cattivo design?

Un altro buon esempio sono le funzioni e le chiusure di prima classe:

scala> def f1(w:Double) = (d:Double) => math.sin(d) * w
f1: (w: Double)(Double) => Double

scala> def f2(w:Double, q:Double) = (d:Double) => d * q * w
f2: (w: Double,q: Double)(Double) => Double

scala> val l = List(f1(3.0), f2(4.0, 0.5))
l: List[(Double) => Double] = List(<function1>, <function1>)

scala> l.map(_(2))
res0: List[Double] = List(2.727892280477045, 4.0)

Java non supporta le funzioni di prima classe e imitare le chiusure con classi interne anonime non è molto elegante. Un'altra cosa che questo esempio mostra che java non può fare è eseguire codice da un interprete / REPL. Lo trovo immensamente utile per testare rapidamente frammenti di codice.


Si prega di notare che il setaccio è troppo lento per essere pratico.
Elazar Leibovich

@oxbow_lakes non esiste un java equivalente per questi esempi.
dbyrne

@dbyme Non è vero. Puoi facilmente sottoclassare Java Iterablee Iteratorprodurre flussi infiniti.
Daniel C. Sobral,

@dbyrne "Un'altra cosa che questo esempio mostra che java non può fare è eseguire codice da un interprete / REPL. Lo trovo immensamente utile per testare rapidamente frammenti di codice." Uso una pagina di album in Eclipse per provare frammenti di Java. Poiché la maggior parte, se non tutto, Java funziona in quell'IDE, non ho bisogno di REPL. Ho usato notepad.exe e javac nei miei primi giorni, quando non ero sicuro di una funzionalità di lingua o libreria e dopo un breve periodo è andato molto bene e velocemente, sebbene un REPL sia un po 'più facile da usare e più veloce. Avrei potuto evitare del tutto l'hack del blocco note installando VisualAge che avevamo già

0

Questo codice Scala ...

def partition[T](items: List[T], p: (T, T) => Boolean): List[List[T]] = {
  items.foldRight[List[List[T]]](Nil)((item: T, items: List[List[T]]) => items match {
    case (first :: rest) :: last if p (first, item) =>
      (List(item)) :: (first :: rest) :: last
    case (first :: rest) :: last =>
      (item :: first :: rest) :: last
    case _ => List(List(item))
  })
}

... sarebbe completamente illeggibile in Java, se possibile.


10
LA MIA OPINIO corretta: grazie per la risposta! ma potresti spiegare cosa succede lì? Non ho ancora familiarità con la sintassi Scala e (questo è il possibile motivo per cui) sembra completamente illeggibile anche adesso per me.
Roman

È il partizionamento di un elenco generico di tipo T utilizzando una funzione di partizionamento fornita come guardia nelle clausole di corrispondenza dei modelli dell'istruzione case.
SOLO LA MIA OPINIONE corretta

3
Strano. Non sono nemmeno lontanamente un esperto di Scala e posso capirlo.
SOLO LA MIA OPINIONE corretta
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.