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 vraiment 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 que Scala sample avec des commentaires du genre" ceci est abstract factory en Scala, en Java cela paraîtra beaucoup plus encombrant " alors cela est aussi acceptable.
Merci!
j'aime le plus tous acceptés et ce réponses
18 réponses
améliorons exemple de stacker et utilisez les "classes de cas de Scala :
case class Person(firstName: String, lastName: String)
la classe Scala ci - dessus contient toutes les caractéristiques de la classe Java ci-dessous, et un peu plus - par exemple, il soutient correspondance de modèle (que Java n'a pas). Scala 2.8 Ajoute les arguments named et default, qui sont utilisés pour générer une méthode de copie pour case classes, 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'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 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)
tâche: Écrire un programme pour indexer une liste de mots clés (comme des livres).
explication:
- Entrée: List
- Sortie: Carte < Character, List
> - la clé de la carte est' A 'à' Z '
- chaque liste dans 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)
}
tâche:
vous avez une liste people
d'objets de la classe Person
qui a les champs name
et age
. Votre tâche est de trier cette liste par name
, et puis 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))
mise à jour
depuis que j'ai écrit cette réponse, il y a eu beaucoup de progrès. Les lambdas (et les références de méthode)ont finalement atterri en Java, et ils prennent le monde de Java par la tempête.
voici à quoi ressemblera le code ci-dessus avec Java 8 (contribution de @fredoverlow):
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 le Scala.
en solution Scala, la méthode Seq[A]#sortBy
accepte une fonction A => B
où B
est requis pour ont an Ordering
. Ordering
est une classe de type. Pensez 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'ont pas. Comme Java n'a 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 la commande et B la commande, alors leur tuple (A, B) a aussi la commande". En code, c'est-à-dire:
implicit def pairOrdering[A : Ordering, B : Ordering]: Ordering[(A, B)] = // impl
c'est ainsi que sortBy
dans notre code peut se comparer par le nom et puis par l'âge. Ceux sémantique sera codé avec la "règle". Un programmeur aurait Scala attendez que cela fonctionne de cette façon. Aucune méthode particulière telle que comparing
n'a dû être ajoutée à Ordering
.
Lambdas and method references ne sont que la pointe d'un iceberg qui est la programmation fonctionnelle. :)
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 les zones firstName
et lastName
de tous les employés.
Java: [ tiré 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: [tiré de ici , diapositive #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é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 ta réponse et te laisser la supprimer si elle te dérange.
C'est comment j'allais le faire 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]);
}
}
c'est juste un piratage rapide impliquant pas de magie et tous les composants réutilisables. Si je voulais ajouter un peu de magie, je pourrais faire quelque chose de mieux que de retourner un tableau de tableaux de cordes, mais même comme C'est le cas, ce GoodXMLLib serait complètement réutilisable. Le premier paramètre de scanFor est la section, tous les paramètres futurs seraient les éléments à trouver qui est limité, mais l'interface peut être légèrement tamponné pour ajouter plusieurs niveaux de correspondance sans problème réel.
j'admets que Java a un support de bibliothèque assez pauvre en général,mais allez -- pour comparer une utilisation horrible de la décennie de Java(?) une ancienne bibliothèque XML à une implémentation basée sur la terse n'est pas juste--et est loin d'être 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<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 les meilleures goût!
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();
j'ai aimé ce simple exemple de tri 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: 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)
j'écris un jeu de Blackjack à Scala maintenant. Voici comment ma méthode dealerWins ressemblerait en Java:
boolean dealerWins() {
for(Player player : players)
if (player.beats(dealer))
return false;
return true;
}
Voici à quoi il ressemble en 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));
}
j'ai aimé utilisateur inconnu réponse tellement 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)
}
j'aime beaucoup la méthode getOrElseUpdate, trouvée dans mutablmap 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 - nombre de mots, et ici en 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 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é indiqué, mais regardez comme c'est facile, ils sont intégrés à 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)
}
c'est un exemple très simple: entiers carrés et puis les ajouter
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:
Array(1,2,3).map(square)
Array[Int] = Array(1, 4, 9)
Fold left is commencera avec 0 comme l'accumulateur (s) et appliquera add(s,i)
à tous les éléments (i) du réseau, de sorte que:
Array(1,4,9).foldLeft(0)(add) // return 14 form 0 + 1 + 4 + 9
maintenant, cela peut être compacté à nouveau à:
Array(1,2,3).map(x => x * x ).foldLeft(0)((s,i) => s + i )
celui-ci je ne vais pas essayer en Java (à beaucoup de travail), tourner XML à une carte:
<a>
<b id="a10">Scala</b>
<b id="b20">rules</b>
</a>
un autre liner 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)
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 rapide tentative de Scala version. 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))
}
}
problème: vous devez concevoir une méthode qui exécutera n'importe quel code asynchrone donné.
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 Scala (avec 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
}
the Circuit Breaker pattern from la version de Michael Nygard in 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!!!")
}
}
}
que je trouve super sympa. Il semble juste comme un pice de la langue, mais il est un simple mixin dans le CircuitBreaker objet faire 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 les autres langues Google pour" disjoncteur " + votre langue.
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.
je suis en train de préparer un document qui donne plusieurs exemples de code Java et Scala, en utilisant seulement les caractéristiques simples à comprendre de Scala:
Si vous voulez m'ajouter quelque chose, merci de répondre dans les commentaires.
les cours d'eau infinis évalués par la suite 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 qui concerne les flux infinis en Java: est-ce qu'un itérateur infini est une mauvaise conception?
un autre bon exemple sont les fonctions de première classe et les fermetures:
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 supporte pas les fonctions de première classe, et imiter des fermetures avec des classes internes anonymes n'est pas très élégant. Une autre chose que ce l'exemple montre que java ne peut pas faire exécute du code à partir 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 complètement illisible en Java, si possible du tout.