Beispiele für Scala- und Java-Code, bei denen Scala-Code einfacher aussieht / weniger Zeilen enthält?


94

Ich benötige einige Codebeispiele (und ich bin auch sehr neugierig darauf) von Scala- und Java-Code, die zeigen, dass Scala-Code einfacher und prägnanter ist als in Java geschriebener Code (natürlich sollten beide Beispiele das gleiche Problem lösen).

Wenn es nur ein Scala-Beispiel mit einem Kommentar wie "Dies ist eine abstrakte Fabrik in Scala, in Java sieht es viel umständlicher aus" gibt, ist dies ebenfalls akzeptabel.

Vielen Dank!

Ich mag am liebsten akzeptiert und diese Antworten


3
Mit ein wenig Beinarbeit finden Sie möglicherweise viele Beispiele auf rosettacode.org
nicerobot

4
Wie kann es eine richtige Antwort auf diese Art von Frage geben?
Polygenelubricants

@polygenelubricants: und was schlägst du vor?
Roman

10
@ Roman: Wir erwarten, dass Scala prägnanter wird. Es wäre interessanter, wenn Sie etwas finden könnten, das in Java präziser ausgedrückt wird als in Scala.
Randall Schulz

1
@ Randall Schulz: Jeder weiß, dass Scala prägnanter ist, aber manchmal brauchen wir aus akademischen Gründen einen Beweis mit Beispielen und Hintergrundtheorie.
Roman

Antworten:


76

Lassen Sie uns das Beispiel des Staplers verbessern und die Fallklassen von Scala verwenden :

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

Die obige Scala-Klasse enthält alle Funktionen der folgenden Java-Klasse und einige weitere - zum Beispiel unterstützt sie den Mustervergleich (den Java nicht hat). Scala 2.8 fügt benannte und Standardargumente hinzu, mit denen eine Kopiermethode für Fallklassen generiert wird, die die gleichen Funktionen wie die with * -Methoden der folgenden Java-Klasse bietet.

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 + ")";
    }
}

Dann haben wir im Gebrauch (natürlich):

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

Gegen

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

2
In 2.7.x und 2.8.0 ist das einzige Boxen in productElementsund unapplynicht im Konstruktor, Feld oder Accessor: gist.github.com/424375
retronym

2
Ermutigt alle Arten von Getter / Setter-Schlechtigkeit. Setter sollten nur mit äußerster Zurückhaltung hinzugefügt werden, Getter sollten nur bei Bedarf hinzugefügt werden. Gutes Beispiel dafür, wie das Hinzufügen von "Einfachheit" zu schlechten Gewohnheiten führt.
Bill K

7
@ Bill K: OK, dann haben wir case class Person(val firstName: String, val lastName: String) Na und? Das Ding privat zu machen wäre auch möglich, macht aber keinen Sinn, weil es nicht zutrifft usw.
soc

1
@shiva case class Person(private val firstName: String), aber Sie sollten dann keine Fallklassen verwenden . Stattdessen tun class Person(firstName: String)und firstNameist standardmäßig privat.
Nilskp

1
@shiva Nein. Der Unterschied zwischen valund private valbesteht darin, ob die Zugriffsmethoden , dh firstName()und firstName(String), öffentlich oder privat sind. In Scala sind Felder immer privat. Damit Scala get / set-Methoden im Java-Stil (zusätzlich zu den Accessoren im Scala-Stil) generieren kann, gibt es die @BeanPropertyAnmerkung.
Esko Luontola

45

Ich fand das beeindruckend

Java

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)

Sowie diese (Entschuldigung, dass ich nicht eingefügt habe, ich wollte den Code nicht stehlen)


Dieser Scala-Code wird nicht generiert getFirstNameund getLastNameMethoden. Dazu müssen Sie die Parameter mit scala.reflect.BeanPropertyAnmerkungen versehen .
Abhinav Sarkar

7
@ abhin4v: Ja, aber der Code-Konvention in Scala ist, dass Accessoren kein Präfix vorangestellt wird get. Der idiomatische Java-Code unterscheidet sich vom idiomatischen Scala-Code. Manchmal das isPräfix für Boolesche Werte. davetron5000.github.com/scala-style/naming_conventions/methods/…
Esko Luontola

6
Sie könnten das a machen case classund das bekommen toString, equalsund das hashCodekostenlos (und Sie müssen die Argumente auch nicht valexplizit vorbringen):case class Person(firstName: String, lastName: String)
Jesper

@shiva, für case class, nicht nur für class.
Nilskp

23

Aufgabe: Schreiben Sie ein Programm, um eine Liste von Schlüsselwörtern (wie Bücher) zu indizieren.

Erläuterung:

  • Eingabe: Liste <String>
  • Ausgabe: Map <Zeichen, Liste <Zeichenfolge >>
  • Der Schlüssel der Karte ist "A" bis "Z".
  • Jede Liste in der Karte ist sortiert.

Java:

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)
}

Sie können v.sorted anstelle von (v sortBy identity) verwenden.
Eastsun

1
Und mit Scala 2.8 können Sie mapValues ​​(_.sorted) anstelle von map {case ...} verwenden
Alex Boisvert

10
Mit Java 8 ist der Code fast identisch mit Scalas: keywords.stream (). Sorted (). Collect (Collectors.groupingBy (it -> it.charAt (0))); macht den Trick!
Der Koordinator

11

Aufgabe:

Sie haben eine Liste peoplevon Klassenobjekten Personmit Feldern nameund age. Ihre Aufgabe ist es, diese Liste zuerst nach nameund dann nach zu sortieren 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))

Aktualisieren

Seit ich diese Antwort geschrieben habe, sind einige Fortschritte zu verzeichnen. Die Lambdas (und Methodenreferenzen) sind endlich in Java gelandet und erobern die Java-Welt im Sturm.

So sieht der obige Code mit Java 8 aus (Beitrag von @fredoverflow):

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

Obwohl dieser Code fast so kurz ist, funktioniert er nicht ganz so elegant wie der Scala-Code.

In Scala Lösung, die Seq[A]#sortByakzeptiert Verfahren eine Funktion , A => Bwo Berforderlich ist , haben , ein Ordering. Orderingist eine Typklasse. Denken Sie am besten an beide Welten: ComparableEs ist implizit für den betreffenden Typ, aber Comparatores ist erweiterbar und kann nachträglich zu Typen hinzugefügt werden, die es nicht hatten. Da Java keine Typklassen hat, muss es jede solche Methode einmal für Comparable, dann für duplizieren Comparator. Zum Beispiel siehe comparingund thenComparing hier .

Mit den Typklassen kann man Regeln schreiben wie "Wenn A eine Reihenfolge hat und B eine Reihenfolge hat, dann hat auch ihr Tupel (A, B) eine Reihenfolge". Im Code heißt das:

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

So können die sortByin unserem Code nach Namen und dann nach Alter verglichen werden. Diese Semantik wird mit der obigen "Regel" codiert. Ein Scala-Programmierer würde intuitiv erwarten, dass dies so funktioniert. Es comparingmussten keine speziellen Methoden wie hinzugefügt werden Ordering.

Lambdas und Methodenreferenzen sind nur eine Spitze eines Eisbergs, der funktionale Programmierung ist. :) :)


Fehlende Lambdas (oder zumindest Methodenreferenzen) sind das wichtigste Merkmal, das ich in Java vermisse.
Petr Gladkikh

@fredoverflow Vielen Dank, dass Sie das Java 8-Beispiel hinzugefügt haben. Es zeigt immer noch, warum Scalas Ansatz überlegen ist. Ich werde später mehr hinzufügen.
Fehlender Faktor

@rakemous, Kumpel, die Antwort wurde vor mehr als sechs Jahren geschrieben.
fehlender Faktor

10

Aufgabe:

Sie haben eine XML-Datei "company.xml", die folgendermaßen aussieht:

<?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>

Sie müssen diese Datei lesen und die Felder firstNameund lastNamealler Mitarbeiter ausdrucken .


Java: [von hier genommen ]

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: [von hier genommen , Folie Nr. 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 von Bill; Überprüfen Sie die Kommentare für die Diskussion] -

Hmm, wie geht das, ohne in einem unformatierten Antwortbereich zu antworten ... Hmph. Ich denke, ich werde Ihre Antwort bearbeiten und Sie sie löschen lassen, wenn es Sie nervt.

So würde ich es in Java mit besseren Bibliotheken machen:

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]);
    }
} 

Dies ist nur ein schneller Hack, der keine Magie und alle wiederverwendbaren Komponenten beinhaltet. Wenn ich etwas Magie hinzufügen wollte, könnte ich etwas Besseres tun, als ein Array von String-Arrays zurückzugeben, aber so wie es ist, wäre GoodXMLLib vollständig wiederverwendbar. Der erste Parameter von scanFor ist der Abschnitt. Alle zukünftigen Parameter sind die zu findenden Elemente, die begrenzt sind. Die Benutzeroberfläche kann jedoch leicht poliert werden, um mehrere Übereinstimmungsstufen ohne wirkliches Problem hinzuzufügen.

Ich gebe zu, dass Java im Allgemeinen eine ziemlich schlechte Bibliotheksunterstützung hat, aber es ist einfach nicht fair, eine schreckliche Verwendung von Javas jahrzehntelanger (?) Alter XML-Bibliothek mit einer Implementierung zu vergleichen, die darauf basiert, knapp zu sein aus einem Vergleich der Sprachen!


hmm, das Java-Beispiel wäre kürzer und würde mit einem SAX- oder StAX-Parser besser aussehen. Aber immer noch ist die SCALA wirklich schön
oluies

5
Der Java-Code wurde genau geschrieben, um diese bestimmte XML-Datei ohne Wiederverwendungsversuch und mit viel dupliziertem Code zu analysieren. Wer auch immer es schrieb, versuchte entweder absichtlich so auszusehen, als würde er die Codierung nicht verstehen oder die Codierung nicht verstehen.
Bill K

@ Bill K: Ich habe noch nie XML-Parsing in Java durchgeführt, daher habe ich dieses Beispiel von einer zufälligen Site ausgewählt. Fühlen Sie sich frei, den Java-Teil der Antwort zu bearbeiten, es macht mir nichts aus.
fehlender Faktor

Nehmen wir an, Sie sprechen von Sprachunterschieden und nicht von Bibliotheksunterschieden - in diesem Fall wären die beiden nahezu identisch. Der einzige Sprachunterschied im zweiten Beispiel ist die Übereinstimmung / Groß- / Kleinschreibung, die in einer einzelnen Zeile als for-Schleife ausgeführt werden kann, wenn sie von der Bibliothek auf diese Weise implementiert wird.
Bill K

@ Bill K: Nein, du liegst völlig falsch. Hier arbeiten zwei sehr leistungsstarke Scala-Funktionen: 1. XML-Literale 2. Mustervergleich. Java hat keine davon. Der entsprechende Java-Code, der in einer hypothetischen Bibliothek geschrieben ist, ist also NICHT identisch. (Versuchen Sie zu schreiben, Sie werden wissen.)
Fehlender Faktor

10

Eine Karte der Aktionen, die abhängig von einer Zeichenfolge ausgeführt werden sollen.

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()

Und das alles nach bestem Geschmack!

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, ich denke deine Bearbeitung ist falsch. todos.get("hi")Gibt zurück, Option[()=>Unit]was für eine ordnungsgemäße Übereinstimmung erforderlich ist.
Huynhjl

@huynhjl, mein schlechtes. Rollte es zurück.
Fehlender Faktor

3
Kann noch kürzer sein:val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
Geoff Reedy

2
Noch kürzer: val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }und danntodos("hi")()
Martin Ring

8

Ich schreibe gerade ein Blackjack-Spiel in Scala. So würde meine DealerWins-Methode in Java aussehen:

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

So sieht es in Scala aus:

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

Hurra für Funktionen höherer Ordnung!

Java 8-Lösung:

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

Scala hat eine sehr schwierige Syntax. Ich muss mich so sehr erinnern :-(
AZ_

Scala ist wie CSS, um viele Attribute und Eigenschaften zu merken
AZ_

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

7

Ich mochte dieses einfache Beispiel für Sortieren und Transformieren aus David Pollaks Buch "Beginning Scala":

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

Wie wäre es mit Quicksort?


Java

Das folgende Java-Beispiel wurde über eine Google-Suche gefunden.

Die URL lautet 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

Ein schneller Versuch einer Scala-Version. Offene Saison für Codeverbesserer; @)

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
Hat diese Quicksortierung auf verknüpften Listen eine O (n ^ 2) -Zeitkomplexität oder nicht? Normalerweise wird Mergesort oder ähnliches für verknüpfte Listen verwendet.
Esko Luontola

3
Es ist auch nicht rekursiv und daher als performanter Algorithmus (oder einer, der den Stapel nicht überläuft)
ungeeignet

Danke für die nützlichen Kommentare. Ich hatte irgendwo so geschriebenes Quicksort gesehen und war beeindruckt von seiner Kompaktheit, offensichtlich habe ich nicht viel darüber nachgedacht. Der LOC-Vergleich hat mich mitgerissen, was bei Scala v Java immer verführerisch ist.
Don Mackenzie

2
Quicksort ist nicht O (n ^ 2) auf Funktionslisten, aber es hat sicherlich diese Gefahr. Asymptotisch ist es immer noch das durchschnittliche O (n log n) , aber es gibt eine höhere statistische Wahrscheinlichkeit, den ungünstigsten Fall O (n ^ 2) zu treffen, da wir immer den Drehpunkt am Anfang der Liste auswählen, anstatt einen zufällig auszuwählen .
Daniel Spiewak

Zweimal filtern ist schlecht. Sehen Sie in meiner Antwort auf Ihre Frage, partitionwie Sie dies vermeiden können.
Daniel C. Sobral

6

Die Antwort von Benutzer unbekannt hat mir so gut gefallen , dass ich versuchen werde, sie zu verbessern. Der folgende Code ist keine direkte Übersetzung des Java-Beispiels, führt jedoch dieselbe Aufgabe mit derselben API aus.

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)
}

Ich habe noch kein Scala-2.8 installiert, um dieses Snippet zu testen, aber ich denke, ich kann sehen, was beabsichtigt ist - nur "Schlüsselwörter" werden überhaupt nicht verwendet. Es wird eine Karte aller Strings und ihrer Frequenzen erstellt, nicht wahr?
Benutzer unbekannt

@user Ja, das ist was es tut. Ist es nicht das, was Ihr Code erreicht? Oh, ich verstehe. Ich habe die falsche Zeile kopiert. Ich werde es jetzt reparieren. :-)
Daniel C. Sobral

6

Ich mag die Methode getOrElseUpdate, die in mutableMap gefunden und hier gezeigt wird, zuerst Java, ohne:

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;
}

ja - ein WordCount und hier 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
}

Und hier ist es 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;
}

Und wenn Sie 100% funktionsfähig sein möchten:

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);
}

filterund sortwurden bereits gezeigt, aber schauen Sie, wie einfach sie in die Karte integriert werden:

    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)
    } 

Ich mag dieses Beispiel sehr. Es vermeidet den einfachen Weg, Fallklassen zu vergleichen, und macht nicht den Fehler, Scala-Code und nicht das Java-Äquivalent anzuzeigen.
Daniel C. Sobral

5

Dies ist ein sehr einfaches Beispiel: Quadratische Ganzzahlen und fügen Sie sie dann hinzu


    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)

Compact Map wendet die Funktion auf alle Elemente des Arrays an.

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

Nach links falten wird mit 0 als Akkumulator (en) beginnen und add(s,i)auf alle Elemente (i) des Arrays angewendet, so dass:

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

Dies kann nun weiter verdichtet werden auf:

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

Dieses werde ich nicht in Java versuchen (zu viel Arbeit), XML in eine Map verwandeln:


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

Ein weiterer Liner, um die Karte aus dem XML zu erhalten:


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)

Das Problem mit Ihrem sumSquarein Scala ist, dass es für einen Java-Entwickler sehr kryptisch aussieht, was ihm Munition gegen Sie gibt, um sich zu beschweren, dass Scala dunkel und kompliziert ist ...
Jesper

Ich habe etwas neu formatiert, um das Beispiel zu verbessern. Hoffe, dass dies Scala nicht schadet.
Thomas

5
scala> 1 bis 10 map (x => x * x) sum res0: Int = 385 Mal sehen, wie der Java-Entwickler das als kryptisch bezeichnet. An diesem Punkt sagen die Finger in den Ohren nah-nah-nah.
PSP

3
@Jesper Für einen Nicht-Java-Entwickler sieht Java wie eine große Menge an Boilerplate- und Leitungsrauschen aus. Das bedeutet nicht, dass Sie keine echte Arbeit in der Sprache erledigen können.
James Moore

Sie können reductLeft (add) anstelle von foldLeft (0) (add) verwenden. Ich denke, es ist einfacher zu lesen, wenn Ihr Startelement das Null- / Identitätselement der Gruppe ist.
Debilski

5

Problem: Sie müssen eine Methode entwerfen, die einen bestimmten Code asynchron ausführt.

Lösung 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
            }
});

Das Gleiche in Scala (mit Schauspielern):

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
Ab 2.8 kann dies als Futures.future {body} geschrieben werden und ist tatsächlich leistungsfähiger, da die dadurch zurückgegebene Zukunft verbunden werden kann, um den Wert zu erhalten, zu dem sie schließlich ausgewertet wird.
Dave Griffith

3

Das Leistungsschaltermuster aus Michael Nygards Release It in FaKods ( Link zum Code )

Die Implementierung in Scala sieht folgendermaßen aus:

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


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

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

Was ich super schön finde. Es sieht nur wie ein Teil der Sprache aus, ist aber eine einfache Mischung im CircuitBreaker-Objekt , die alle Arbeiten ausführt .

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

Referenz in anderen Sprachen Google für "Leistungsschalter" + Ihre Sprache.


3

Ich bereite ein Dokument vor, das mehrere Beispiele für Java- und Scala-Code enthält und nur die einfach zu verstehenden Funktionen von Scala verwendet:

Scala: Ein besseres Java

Wenn Sie möchten, dass ich etwas hinzufüge, antworten Sie bitte in den Kommentaren.


Titel "Scala: Ein besseres Java" ist irreführend
Entenjagd

2

Warum das noch niemand gepostet hat:

Java:

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

116 Zeichen.

Scala:

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

56 Zeichen.


1
ApplicationEigenschaft als schädlich angesehen ... scala-blogs.org/2008/07/…
fehlender Faktor

1

Faul bewertete unendliche Ströme sind ein gutes Beispiel:

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

}

Hier ist eine Frage zu unendlichen Streams in Java: Ist ein unendlicher Iterator ein schlechtes Design?

Ein weiteres gutes Beispiel sind erstklassige Funktionen und Verschlüsse:

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 unterstützt keine erstklassigen Funktionen, und die Nachahmung von Abschlüssen mit anonymen inneren Klassen ist nicht sehr elegant. Eine andere Sache, die dieses Beispiel zeigt, dass Java nicht kann, ist das Ausführen von Code von einem Interpreter / REPL. Ich finde das immens nützlich, um Code-Schnipsel schnell zu testen.


Bitte beachten Sie, dass das Sieb zu langsam ist, um praktisch zu sein.
Elazar Leibovich

@oxbow_lakes Für diese Beispiele gibt es kein gleichwertiges Java.
Dbyrne

@dbyme Nicht wahr. Sie können Java einfach in Unterklassen unterteilen Iterableund Iteratorunendliche Streams erzeugen.
Daniel C. Sobral

@dbyrne "Eine andere Sache, die dieses Beispiel zeigt, dass Java nicht in der Lage ist, Code von einem Interpreter / REPL auszuführen. Ich finde dies immens nützlich, um Code-Schnipsel schnell zu testen." Ich benutze eine Scrapbook-Seite in Eclipse, um Java-Snippets auszuprobieren. Da die meisten, wenn nicht alle Java-Funktionen in dieser IDE ausgeführt werden, benötige ich keine REPL. Ich habe notepad.exe und javac in meinen frühen Tagen verwendet, als ich mir über eine Sprach- oder Bibliotheksfunktion nicht sicher war, und nach kurzer Zeit ging das sehr gut und schnell - obwohl eine REPL etwas einfacher zu verwenden ist - und schneller. Ich hätte den Notepad-Hack ganz vermeiden können, indem ich VisualAge installiert hätte, das wir bereits hatten

0

Dieser Scala-Code ...

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))
  })
}

... wäre in Java, wenn möglich, überhaupt nicht lesbar.


10
MEIN korrektes OPINIO: Danke für die Antwort! Aber können Sie bitte erklären, was dort passiert? Ich bin noch nicht mit der Scala-Syntax vertraut und (das ist der mögliche Grund dafür) sieht sie auch jetzt noch für mich völlig unlesbar aus.
Roman

Es partitioniert eine generische Liste vom Typ T unter Verwendung einer bereitgestellten Partitionierungsfunktion als Schutz in den Mustervergleichsklauseln der case-Anweisung.
Nur meine richtige Meinung

3
Seltsam. Ich bin nicht einmal im entferntesten ein Scala-Experte und kann das herausfinden.
NUR MEINE korrekte MEINUNG
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.