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


94

J'ai besoin de quelques exemples de code (et je suis 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 (bien sûr, les deux exemples devraient résoudre le même problème).

S'il n'y a qu'un exemple Scala avec un commentaire comme "c'est une fabrique abstraite dans Scala, en Java cela aura l'air beaucoup plus encombrant" alors c'est également acceptable.

Merci!

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


3
Avec un peu de travail sur les jambes, vous trouverez peut-être beaucoup d'échantillons sur rosettacode.org
nicerobot

4
Comment peut-il y avoir une réponse correcte à ce genre de question?
polygenelubricants

@polygenelubricants: et que suggérez-vous?
Roman

10
@Roman: Nous nous attendons à ce que Scala soit plus concis. Ce serait plus intéressant si vous pouviez trouver quelque chose d'exprimé de manière plus concise en Java qu'en Scala.
Randall Schulz

1
@Randall Schulz: tout le monde sait que Scala est plus concis, mais parfois, à des fins académiques, nous avons besoin d'une preuve avec des exemples et une théorie de base.
Roman

Réponses:


76

Améliorons l'exemple de empileur et l' utilisation de Scala classes de cas :

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

La classe Scala ci-dessus contient toutes les fonctionnalités de la classe Java ci-dessous, et d'autres - par exemple, elle prend en charge la correspondance de modèles (ce 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 la même capacité que les méthodes with * de la classe Java suivante.

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

Ensuite, dans l'utilisation, 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)

2
Dans 2.7.x et 2.8.0, la seule boxe est dans productElementset unapply, pas dans le constructeur, le champ ou l'accesseur: gist.github.com/424375
retronym

2
Encourage toutes sortes de méchanceté de getter / setter. Les setters ne doivent être ajoutés qu'avec une extrême réticence, les getters ne doivent être ajoutés que si nécessaire. Bon exemple de la façon dont l'ajout de «simplicité» conduit à de mauvaises habitudes.
Bill K

7
@Bill K: OK, alors nous aurons case class Person(val firstName: String, val lastName: String) Et alors? Rendre cette chose privée serait également possible, mais n'a aucun sens, à cause de l'inapplication, etc.
soc

1
@shiva case class Person(private val firstName: String), mais vous ne devriez pas utiliser de classes de cas alors. Au lieu de cela, faites class Person(firstName: String)et firstNameest privé par défaut.
nilskp

1
@shiva Non. La différence entre valet private valest que les méthodes d' accès , c'est firstName()-à- dire et firstName(String), sont publiques ou privées. Dans Scala, les champs sont toujours privés. Pour que Scala génère des méthodes get / set de style Java (en plus des accesseurs de style Scala), il y a l' @BeanPropertyannotation.
Esko Luontola le

45

J'ai trouvé celui-ci impressionnant

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)

En plus de ceux-ci (désolé de ne pas coller, je ne voulais pas voler le code)


Ce code scala ne génère pas getFirstNameet getLastNameméthodes. Vous devez annoter les paramètres avec une scala.reflect.BeanPropertyannotation pour ce faire.
Abhinav Sarkar

7
@ abhin4v: Oui, mais la convention de code dans Scala est de ne pas avoir d'accesseurs préfixés par get. Le code Java idiomatique est différent du code idiomatique Scala. Parfois, le ispréfixe utilisé pour les booléens. davetron5000.github.com/scala-style/naming_conventions/methods/…
Esko Luontola

6
Vous pouvez en faire un case classet obtenir le toString, equalset hashCodegratuitement (et vous n'avez pas non plus à faire valoir valexplicitement les arguments ):case class Person(firstName: String, lastName: String)
Jesper

@shiva, pour case class, pas pour juste class.
nilskp

23

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

Explication:

  • Entrée: List <String>
  • Sortie: Map <Character, List <String>>
  • La clé de la carte est 'A' à 'Z'
  • Chaque liste de la carte est triée.

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

Vous pouvez utiliser v.sorted au lieu de (v sortBy identity).
Eastsun

1
Et avec Scala 2.8, vous pouvez utiliser mapValues ​​(_.sorted) au lieu de map {case ...}
Alex Boisvert

10
Avec Java 8, le code est presque identique à Scalas: keywords.stream (). Sorted (). Collect (Collectors.groupingBy (it -> it.charAt (0))); fait l'affaire!
The Coordinator

11

Tâche:

Vous avez une liste peopled'objets de classe Personqui a des champs nameet age. Votre tâche consiste à trier cette liste d'abord par name, puis par 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))

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éthodes) ont enfin atterri à Java et prennent d'assaut le monde Java.

Voici à quoi ressemblera le code ci-dessus avec Java 8 (contribué 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 Seq[A]#sortByméthode accepte une fonction A => Boù il Best nécessaire d' avoir un Ordering. Orderingest une classe de type. Pensez au mieux aux deux mondes: comme Comparable, c'est implicite pour le type en question, mais comme Comparator, c'est extensible et peut être ajouté rétrospectivement aux types qui ne l'avaient pas. Comme Java manque de classes de types, il doit dupliquer chacune de ces méthodes, une fois pour Comparable, puis pour Comparator. Par exemple, voir comparinget 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 également un ordre". Dans le code, c'est-à-dire:

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

C'est ainsi que le sortBydans notre code peut comparer par nom puis par âge. Cette sémantique sera encodée 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 celle-ci comparingn'a dû être ajoutée Ordering.

Les lambdas et les références de méthodes ne sont que la pointe d'un iceberg qui est la programmation fonctionnelle. :)


Les lambdas manquants (ou au moins les références de méthode) sont la caractéristique la plus importante qui me manque en Java.
Petr Gladkikh le

@fredoverflow Merci d'avoir ajouté l'exemple Java 8. Cela démontre toujours pourquoi l'approche de Scala est supérieure. J'ajouterai plus tard.
missingfaktor

@rakemous, mec, la réponse a été écrite il y a plus de six ans.
missingfaktor

10

Tâche:

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

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

Vous devez lire ce fichier et imprimer le firstNameetlastName champs de tous les employés.


Java: [tiré d' 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(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: [prise d' ici , diapositive n ° 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)
        } 
      }
    }
  }
}

[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 dérange.

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

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

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

J'admets que Java a un support de bibliothèque assez médiocre en général, mais allez - comparer une utilisation horrible de la bibliothèque XML vieille de dix ans (?) De Java à une implémentation basée sur le fait d'être laconique n'est tout simplement pas juste - et c'est loin à partir d'une comparaison des langues!


hmm, l'exemple Java serait plus court et plus beau avec un analyseur SAX ou StAX. Mais toujours le SCALA est vraiment sympa
oluies

5
Le code Java est écrit exactement pour analyser ce fichier XML particulier sans tentative de réutilisation et avec beaucoup de code dupliqué. Celui qui l'a écrit essayait de donner délibérément l'impression de ne pas comprendre le codage ou de ne pas comprendre le codage.
Bill K

@Bill K: Je n'ai jamais fait d'analyse XML en Java, j'ai donc choisi cet exemple sur un site aléatoire. N'hésitez pas à modifier la partie Java de la réponse, cela ne me dérange pas.
missingfaktor

Eh bien, supposons que vous parlez de différences de langue et non de différences de bibliothèque - dans ce cas, les deux seraient presque identiques. La seule différence de langage dans le deuxième exemple est la chose match / case qui pourrait être effectuée en une seule ligne comme une boucle for si elle est implémentée de cette façon par la bibliothèque.
Bill K

@Bill K: Non, vous vous trompez complètement. Il y a deux fonctionnalités Scala très puissantes à l'œuvre ici: 1. XML Literals 2. Pattern Matching. Java n'a ni l'un ni l'autre. Ainsi, le code Java équivalent écrit dans une bibliothèque hypothétique ne sera certainement PAS identique. (Essayez d'écrire, vous saurez.)
missingfaktor

10

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

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

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, je pense que votre modification est incorrecte. todos.get("hi")renvoie Option[()=>Unit]ce qui est nécessaire pour correspondre correctement.
huynhjl

@huynhjl, mon mauvais. Je l'ai roulé en arrière.
missingfaktor

3
Peut être encore plus court:val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
Geoff Reedy

2
Encore plus court: val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }et puistodos("hi")()
Martin Ring

8

J'écris un jeu de Blackjack à Scala maintenant. Voici à quoi ressemblerait ma méthode dealerWins en Java:

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

Voici à quoi cela ressemble dans Scala:

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

Hourra pour les fonctions d'ordre supérieur!

Solution Java 8:

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

scala a une syntaxe très difficile. besoin de se souvenir de tant de choses :-(
AZ_

Scala est comme CSS, à de nombreux attributs et propriétés à retenir
AZ_

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

7

J'ai aimé cet exemple simple de tri et de transformation, tiré du livre 'Beginning Scala' de David Pollak:

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

En 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

Et Quicksort?


Java

Ce qui suit est 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éliorateurs 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))
  }
}

1
Ce tri rapide sur les listes chaînées a-t-il une complexité temporelle O (n ^ 2) ou non? Le tri fusionné ou similaire est généralement utilisé pour les listes liées.
Esko Luontola le

3
Ce n'est pas non plus récursif et donc inapproprié en tant
qu'algorithme

Merci pour les commentaires utiles. J'avais vu quicksort écrit comme ça quelque part et j'ai été impressionné par sa compacité, clairement je n'y ai pas accordé beaucoup d'attention. Je me suis laissé emporter par la comparaison LOC, qui est toujours séduisante avec Scala v Java.
Don Mackenzie

2
Quicksort n'est pas O (n ^ 2) sur les listes fonctionnelles, mais il présente certainement ce danger. Asymptotiquement, c'est toujours la moyenne O (n log n) , mais il y a une probabilité statistique plus élevée d'atteindre le pire des cas O (n ^ 2) car nous sélectionnons toujours le point de pivot en tête de la liste, plutôt que d'en choisir un au hasard .
Daniel Spiewak

Filtrer deux fois est mauvais. Voyez dans ma réponse à votre question l'utilisation de partitionpour éviter cela.
Daniel C.Sobral

6

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 accomplit la même tâche avec la même 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)
}

Je n'ai pas encore installé scala-2.8, pour tester cet extrait de code, mais je suppose que je peux voir ce qu'est intentet - seuls les «mots-clés» ne sont pas du tout utilisés. Il produit une carte de toutes les cordes et de leurs fréquences, n'est-ce pas?
utilisateur inconnu le

@user Oui, c'est ce qu'il fait. N'est-ce pas ce qu'accomplit votre code? Oh je vois. J'ai copié la mauvaise ligne. Je vais le réparer maintenant. :-)
Daniel C. Sobral

6

J'aime beaucoup la méthode getOrElseUpdate, trouvée dans mutableMap et montrée ici, d'abord Java, sans:

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

oui - un WordCount, et ici dans 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
}

Et le voici en 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;
}

Et si vous voulez être 100% fonctionnel:

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

filteret sortont déjà été montrés, mais regardez comme ils sont faciles à intégrer à la carte:

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

J'aime beaucoup cet exemple. Cela évite de comparer facilement les classes de cas et ne fait pas l'erreur d'afficher le code Scala et non l'équivalent Java.
Daniel C.Sobral

5

Ceci est un exemple très simple: des 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;
    }

Dans 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 carte compacte 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 commencera par 0 comme accumulateur (s) et s'appliquera 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 n'essaierai pas en Java (trop de travail), transformez XML en Map:


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

Une autre ligne pour obtenir la carte à partir du 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)

Le problème avec votre sumSquareScala est qu'il semble très cryptique pour un développeur Java, ce qui leur donnera des munitions contre vous pour se plaindre que Scala est obscur et compliqué ...
Jesper

J'ai reformaté un peu pour améliorer l'exemple. J'espère que cela ne fait pas de mal à Scala.
Thomas

5
scala> 1 à 10 map (x => x * x) sum res0: Int = 385 Voyons voir le développeur java appeler cela cryptique. À ce stade, ce sont les doigts dans les oreilles qui disent nah-nah-nah.
psp

3
@Jesper Pour un développeur non-Java, Java ressemble à de grandes quantités de bruit standard et de ligne. Cela ne signifie pas que vous ne pouvez pas faire un vrai travail dans la langue.
James Moore

Vous pouvez utiliser reductionLeft (add) au lieu de foldLeft (0) (add). Je pense que c'est plus facile à lire lorsque votre élément de départ est l'élément zéro / identité du groupe.
Debilski

5

Problème: vous devez concevoir une méthode qui exécutera n'importe quel 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 dans 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    
}

6
Depuis la version 2.8, cela peut être écrit comme Futures.future {body} et est en fait plus puissant puisque le futur renvoyé par ceci peut être joint pour obtenir la valeur à laquelle il évalue finalement.
Dave Griffith

3

Le modèle de disjoncteur de Michael Nygard's Release It in FaKods ( lien vers le code )

l'implémentation 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. Cela ressemble à une partie du langage, mais c'est un simple mixin dans l' objet CircuitBreaker qui fait tout le travail.

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

Référence dans d'autres langues Google pour "Disjoncteur" + votre langue.


3

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'y ajoute quelque chose, veuillez répondre dans les commentaires.


Le titre "Scala: A better Java" est trompeur
duckhunt

2

Pourquoi personne n'a publié ça avant:

Java:

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

116 caractères.

Scala:

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

56 caractères.


1
Applicationtrait considéré comme nocif ... scala-blogs.org/2008/07/…
missingfaktor

1

Les flux infinis évalués paresseusement en 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 flux infinis en Java: Un itérateur infini est-il mal conçu?

Les fonctions et fermetures de première classe sont un autre bon exemple:

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 ne prend pas en charge 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 à partir d'un interpréteur / REPL. Je trouve cela extrêmement utile pour tester rapidement des extraits de code.


Veuillez noter que le tamis est trop lent pour être pratique.
Elazar Leibovich

@oxbow_lakes il n'y a pas de java équivalent pour ces exemples.
dbyrne

@dbyme Pas vrai. Vous pouvez facilement sous-classer les Java Iterableet Iteratorproduire des flux infinis.
Daniel C.Sobral

@dbyrne "Une autre chose que cet exemple montre que java ne peut pas faire est d'exécuter du code à partir d'un interpréteur / REPL. Je trouve cela extrêmement utile pour tester rapidement des extraits de code." J'utilise une page d'album dans Eclipse pour essayer des extraits Java. En faisant la plupart sinon tous les travaux de Java dans cet IDE, je n'ai pas besoin de REPL. J'ai utilisé notepad.exe et javac à mes débuts lorsque je n'étais pas sûr d'une fonctionnalité de langage ou de bibliothèque et après un court laps de temps, cela s'est très bien passé et rapidement - bien qu'un REPL soit un peu plus facile à utiliser - et plus rapide. J'aurais pu éviter le piratage du bloc-notes en installant VisualAge que nous avions déjà dans

0

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 complètement illisible en Java, si possible du tout.


10
MON OPINIO correct: merci pour la réponse! mais pourriez-vous s'il vous plaît expliquer ce qui se passe là-bas? Je ne suis pas encore familier avec la syntaxe Scala, et (c'est peut-être la raison pour laquelle) elle semble complètement illisible même maintenant pour moi.
Roman

Il partitionne une liste générique de type T en utilisant une fonction de partitionnement fournie comme garde dans les clauses de correspondance de modèle de l'instruction case.
JUSTE MON AVIS correct

3
Bizarre. Je ne suis même pas un expert Scala à distance et je peux le comprendre.
JUSTE MON OPINION correcte le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.