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


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 échantillon Scala avec un commentaire comme "ceci est une usine abstraite à Scala, en Java, cela aura l'air beaucoup plus lourd", alors c'est également acceptable.

Merci!

J'aime surtout accepté et ce répond

Author: Community, 2010-06-01

18 answers

Améliorons l'exemple de stacker et utilisons les classes de cas de Scala :

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

La classe Scala ci - dessus contient toutes les fonctionnalités de la classe Java ci-dessous, et quelques autres - par exemple, elle prend en charge pattern matching (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 copy method pour les classes de casse, ce qui donne la même capacité que les méthodes with* du Java suivant classe.

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

Alors, 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)
 74
Author: Esko Luontola, 2017-05-23 12:09:14

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)

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

 45
Author: stacker, 2010-06-01 19:43:17

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

Explication:

  • Entrée: Liste
  • Sortie: Carte >
  • 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)
}
 23
Author: missingfaktor, 2012-09-10 16:47:34

Tâche:

Vous avez une liste people d'objets de la classe Person, ce qui a des champs name et 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());
  }
});

Il s'agit d'un jeu de rôle.]}

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

Mise à 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 finalement atterri en Java, et ils prennent d'assaut le monde Java.

C'est à 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 méthode Seq[A]#sortBy accepte une fonction A => BBest requis pour que ait un Ordering. Ordering est une classe de type. Pensez au meilleur des 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'avaient pas. Comme Java manque de classes de type, il doit dupliquer chacune de ces méthodes, une fois pour Comparable, puis pour Comparator. Voir, par exemple, 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 é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 sortBy de notre code peut se comparer par nom puis par âge. Ces sémantiques seront codé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 comparing n'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. :)

 11
Author: missingfaktor, 2015-06-28 12:11:40

Tâche:

Vous avez un fichier XML "société.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 firstName et lastName les champs de tous les employés.


Java: [ prises à partir de 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: [ prises à partir de 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 facture; Vérifier 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 impliquant pas de 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, Xmllib serait complètement réutilisable. Le premier paramètre de scanFor est la section, all future les paramètres seraient les éléments à trouver qui est limité, mais l'interface pourrait être légèrement améliorée pour ajouter plusieurs niveaux de correspondance sans réel problème.

J'admettrai que Java a un assez mauvais support de bibliothèque en général, mais allez compare pour comparer une utilisation horrible de la décennie de Java(?) l'ancienne bibliothèque XML à une implémentation basée sur le fait d'être laconique n'est tout simplement pas juste--et est loin d'être une comparaison des langages!

 10
Author: missingfaktor, 2010-09-06 19:06:51

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();
 8
Author: Ben Hardy, 2014-07-18 21:41:42

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)
 7
Author: Arjan Blokzijl, 2012-07-06 10:40:22

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 ça 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));
}
 7
Author: MikeFHay, 2014-07-18 21:16:51

J'ai aimé utilisateur inconnu du réponse beaucoup je vais essayer de l'améliorer. Le code ci-dessous 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)
}
 6
Author: Daniel C. Sobral, 2017-05-23 12:32:02

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

filter et sort ont déjà été montrés, mais regardez à quel point ils sont intégrés facilement à 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)
    } 
 6
Author: user unknown, 2014-07-18 22:51:29

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)

Compact map applique la fonction à tous les éléments du tableau, donc:

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

Fold left is 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é à:

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

Celui-ci, je ne vais pas essayer en Java( pour beaucoup de travail), tourner XML à une carte:


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

Une autre doublure 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)
 5
Author: Thomas, 2010-06-01 21:10:00

Que diriez-vous de 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))
  }
}
 5
Author: Don Mackenzie, 2010-06-01 22:47:26

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

Solution dans 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    
}
 5
Author: Vasil Remeniuk, 2010-06-02 11:11:19

Le modèle de disjoncteur de Michael Nygard Le libère dans 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. Il ressemble juste à un pice du langage mais c'est un simple mixin dans l'objet CircuitBreaker faisant 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
Author: oluies, 2010-06-04 21:23:49

Pourquoi personne n'a posté ceci 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.

 2
Author: OscarRyz, 2012-07-06 10:49:38

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.

 2
Author: HRJ, 2012-09-13 17:33:23

Les flux infinis évalués paresseusement 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 mauvais design?

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(<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 ce extrêmement utile pour tester rapidement des extraits de code.

 1
Author: dbyrne, 2017-05-23 12:00:13

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.

 0
Author: JUST MY correct OPINION, 2010-06-02 14:14:17