Exemples de code Scala et Java où le code Scala semble plus simple / comporte moins de lignes?

J’ai besoin de quelques exemples de code (et aussi très curieux à leur sujet) de code Scala et Java qui montrent que le code Scala est plus simple et concis que le code écrit en Java (les deux échantillons doivent bien sûr résoudre le même problème).

S’il n’y a que des exemples Scala avec des commentaires comme “ceci est une fabrique abstraite dans Scala, en Java, cela sera beaucoup plus lourd”, alors cela est également acceptable.

Merci!

J’aime plus que tout accepté et cela répond

Améliorons l’exemple de l’emstackur et utilisons les classes de cas de Scala:

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

La classe Scala ci-dessus contient toutes les fonctionnalités de la classe Java ci-dessous, et d’autres encore – par exemple, elle prend en charge la correspondance de modèle (que Java n’a pas). Scala 2.8 ajoute des arguments nommés et par défaut, qui sont utilisés pour générer une méthode de copie pour les classes de cas, ce qui donne les mêmes possibilités que les méthodes with * de la classe Java suivante.

 public class Person implements Serializable { private final Ssortingng firstName; private final Ssortingng lastName; public Person(Ssortingng firstName, Ssortingng lastName) { this.firstName = firstName; this.lastName = lastName; } public Ssortingng getFirstName() { return firstName; } public Ssortingng getLastName() { return lastName; } public Person withFirstName(Ssortingng firstName) { return new Person(firstName, lastName); } public Person withLastName(Ssortingng 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 Ssortingng toSsortingng() { return "Person(" + firstName + "," + lastName + ")"; } } 

Ensuite, dans l’usage, nous avons (bien sûr):

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

Contre

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

J’ai trouvé celui-ci impressionnant

Java

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

Scala

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

Comme ceux-là (désolé de ne pas coller, je ne voulais pas voler le code)

  • Queens-Problème Java
  • Queens-Problème Scala

Tâche: Ecrivez un programme pour indexer une liste de mots-clés (comme les livres).

Explication:

  • Entrée: liste
  • Output: Map >
  • La clé de la carte est ‘A’ à ‘Z’
  • Chaque liste de la carte est sortingée.

Java:

 import java.util.*; class Main { public static void main(Ssortingng[] args) { List keywords = Arrays.asList("Apple", "Ananas", "Mango", "Banana", "Beer"); Map> result = new HashMap>(); for(Ssortingng k : keywords) { char firstChar = k.charAt(0); if(!result.containsKey(firstChar)) { result.put(firstChar, new ArrayList()); } result.get(firstChar).add(k); } for(List 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) } 

Tâche:

Vous avez une liste de people d’objects de classe Person qui ont des champs name et age . Votre tâche consiste à sortinger cette liste d’abord par name , puis par age .

Java 7:

 Collections.sort(people, new Comparator() { public int compare(Person a, Person b) { return a.getName().compare(b.getName()); } }); Collections.sort(people, new Comparator() { 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)) 

Mettre à jour

Depuis que j’ai écrit cette réponse, il y a eu pas mal de progrès. Les lambdas (et les références de méthode) ont finalement atterri à Java et ils ont pris d’assaut le monde de Java.

Voici à quoi ressemblera le code ci-dessus avec Java 8 (fourni par @fredoverflow):

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

Bien que ce code soit presque aussi court, il ne fonctionne pas aussi élégamment que celui de Scala.

Dans la solution Scala, la méthode Seq[A]#sortBy accepte une fonction A => BB doit avoir une Ordering . Ordering est une classe de type. Pensez mieux aux deux mondes: Comme Comparable , il est implicite pour le type en question, mais comme Comparator , il est extensible et peut être ajouté rétrospectivement aux types qui ne l’ont pas. Étant donné que Java ne dispose pas de classes de type, il doit dupliquer toutes ces méthodes, une fois pour Comparable , puis pour Comparator . Par exemple, voir comparing et thenComparing ici .

Les classes de type permettent d’écrire des règles telles que “Si A a un ordre et B un ordre, alors leur tuple (A, B) a aussi un ordre”. Dans le code, c’est:

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

C’est comme ça que le sortBy dans notre code peut se comparer par nom, puis par âge. Ces sémantiques seront encodées avec la “règle” ci-dessus. Un programmeur Scala s’attendrait intuitivement à ce que cela fonctionne de cette façon. Aucune méthode spéciale comme la comparing n’a dû être ajoutée à la Ordering .

Les lambdas et les références de méthode ne sont que la pointe d’un iceberg qui est une functional programming. 🙂

Tâche:

Vous avez un fichier XML “company.xml” qui ressemble à ceci:

    Tom Cruise   Paul Enderson   George Bush   

Vous devez lire ce fichier et imprimer les champs firstName et lastName de tous les employés.

Java: [pris ici ]

 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(Ssortingng[] 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: [pris ici , diapositive # 19]

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

[MODIFIER par Bill; Vérifiez les commentaires pour la discussion] -

Hmm, comment le faire sans répondre dans une section de réponse non formatée ... Hmph. Je suppose que je vais modifier votre réponse et vous laisser la supprimer si elle vous pose problème.

Voici comment je le ferais en Java avec de meilleures bibliothèques:

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

Ceci est juste un hack rapide impliquant pas de magie et de tous les composants réutilisables. Si je voulais append de la magie, je pourrais faire quelque chose de mieux que de renvoyer un tableau de tableaux de chaînes de caractères, mais même si tel est le cas, GoodXMLLib serait complètement réutilisable. Le premier paramètre de scanFor est la section, tous les parameters futurs seraient les éléments à trouver qui sont limités, mais l'interface pourrait être légèrement améliorée pour append plusieurs niveaux de correspondance sans problème réel.

Je dois admettre que Java a un support médiocre de la bibliothèque en général, mais allez - comparer une utilisation horrible de l'ancienne bibliothèque XML de la décennie de Java (?) À une implémentation basée sur le fait d'être laconique n'est pas juste - et c'est loin à partir d'une comparaison des langues!

Une carte des actions à effectuer en fonction d’une chaîne.

Java 7:

 // strategy pattern = syntactic cruft resulting from lack of closures public interface Todo { public void perform(); } final Map todos = new HashMap(); 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() 

Et tout est fait dans le meilleur goût possible!

Java 8:

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

J’ai aimé cet exemple simple de sorting et de transformation, tiré du livre ‘Beginning Scala’ de David Pollak:

En Scala:

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

En Java:

 public static List validByAge(List in) { List people = new ArrayList(); for (Person p: in) { if (p.valid()) people.add(p); } Collections.sort(people, new Comparator() { public int compare(Person a, Person b) { return a.age() - b.age(); } } ); List ret = new ArrayList(); for (Person p: people) { ret.add(p.first); } return ret; } public class Person { private final Ssortingng firstName; private final Ssortingng lastName; private final Integer age; public Person(Ssortingng firstName, Ssortingng lastName, Integer age) { this.firstName = firstName; this.lastName = lastName; this.age = age; } public Ssortingng getFirst() { return firstName; } public Ssortingng getLast() { return lastName; } public Integer getAge() { return age; } public Boolean valid() { return age > 18; } } List input = new ArrayList(); input.add(new Person("John", "Valid", 32)); input.add(new Person("John", "InValid", 17)); input.add(new Person("OtherJohn", "Valid", 19)); List output = validByAge(input) 

J’écris un jeu de blackjack à Scala maintenant. Voici comment ma méthode dealerWins ressemblerait à Java:

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

Voici comment cela se présente à Scala:

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

Hourra pour les fonctions supérieures!

Solution Java 8:

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

J’ai tellement aimé la réponse de l’ utilisateur inconnu que je vais essayer de l’améliorer. Le code ci-dessous n’est pas une traduction directe de l’exemple Java, mais il effectue la même tâche avec la même API.

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

J’aime beaucoup la méthode getOrElseUpdate, trouvée dans mutableMap et présentée ici, en premier Java, sans:

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

oui – un WordCount, et ici en scala:

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

Et la voici en Java 8:

 public static Map wordCount(Scanner sc, Ssortingng delimiters) { Map 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; } 

Et si vous voulez aller 100% fonctionnel:

 import static java.util.function.Function.identity; import static java.util.stream.Collectors.*; public static Map wordCount(Scanner sc, Ssortingng delimiters) { Stream stream = stream(sc.useDelimiter(delimiters)); return stream.collect(groupingBy(identity(), counting())); } public static  Stream stream(Iterator iterator) { Spliterator spliterator = Spliterators.spliteratorUnknownSize(iterator, 0); return StreamSupport.stream(spliterator, false); } 

filter et sort ont déjà été montrés, mais regardez comme ils sont faciles à intégrer à la carte:

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

Voici un exemple très simple: Entiers carrés puis ajoutez-les

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

En 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 applique la fonction à tous les éléments du tableau, donc:

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

Le pli à gauche commence avec 0 comme accumulateur (s) et applique add(s,i) à tous les éléments (i) du tableau, de sorte que:

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

Maintenant, cela peut être encore compacté pour:

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

Celui-ci, je ne vais pas essayer en Java (pour travailler beaucoup), transformez XML en carte:

  Scala rules  

Un autre paquebot pour obtenir la carte du XML:

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

Qu’en est-il de Quicksort?


Java

Voici un exemple Java trouvé via une recherche Google,

l’URL est 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

Une tentative rapide d'une version Scala. Saison ouverte pour les améliorants de code; @)

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

Problème: vous devez concevoir une méthode qui exécutera tout code donné de manière asynchrone.

Solution en 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 même chose à Scala (en utilisant des acteurs):

 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 } 

Le schéma de disjoncteur issu de l’ édition de Michael Nygard dans FaKods ( lien vers le code )

la mise en œuvre ressemble à ceci dans Scala:

 . . . addCircuitBreaker("test", CircuitBreakerConfiguration(100,10)) . . . class Test extends UsingCircuitBreaker { def myMethodWorkingFine = { withCircuitBreaker("test") { . . . } } def myMethodDoingWrong = { withCircuitBreaker("test") { require(false,"FUBAR!!!") } } } 

Ce que je trouve super sympa. Il semble juste comme un morceau du langage mais c’est un simple mixin dans l’ object CircuitBreaker qui fait tout le travail.

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

Référence dans d’autres langues Google pour “Disjoncteur” + votre langue.

Pourquoi personne n’a posté ceci avant:

Java:

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

116 caractères.

Scala:

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

56 caractères.

Je prépare un document qui donne plusieurs exemples de code Java et Scala, en utilisant uniquement les fonctionnalités simples à comprendre de Scala:

Scala: un meilleur Java

Si vous souhaitez que j’ajoute quelque chose, veuillez répondre dans les commentaires.

Les stream infiniment évalués faiblement sont un bon exemple:

 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 } 

Voici une question concernant les stream infinis en Java: un iterator infini est-il une mauvaise conception?

Un autre bon exemple sont les fonctions et les fermetures de première 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(, ) scala> l.map(_(2)) res0: List[Double] = List(2.727892280477045, 4.0) 

Java ne supporte pas les fonctions de première classe, et imiter les fermetures avec des classes internes anonymes n’est pas très élégant. Une autre chose que cet exemple montre que java ne peut pas faire est d’exécuter du code d’un interpréteur / REPL. Je trouve cela extrêmement utile pour tester rapidement des extraits de code.

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

… serait totalement illisible en Java, si possible.