¿Muestras de código Scala y Java donde el código Scala parece más simple / tiene menos líneas?


94

Necesito algunas muestras de código (y también tengo mucha curiosidad por ellas) de código Scala y Java que muestran que el código Scala es más simple y conciso que el código escrito en Java (por supuesto, ambas muestras deberían resolver el mismo problema).

Si solo hay una muestra de Scala con comentarios como "esto es una fábrica abstracta en Scala, en Java se verá mucho más complicado", entonces esto también es aceptable.

¡Gracias!

Me gusta sobre todo aceptado y esto responde


3
Con un poco de trabajo preliminar
nicerobot

4
¿Cómo puede haber una respuesta correcta en este tipo de pregunta?
polygenelubricants

@polygenelubricants: ¿y qué sugieres?
Roman

10
@Roman: Esperamos que Scala sea más conciso. Sería más interesante si pudiera encontrar algo que se expresara de manera más concisa en Java que en Scala.
Randall Schulz

1
@Randall Schulz: todo el mundo sabe que Scala es más conciso, pero a veces, con fines académicos, necesitamos una prueba con ejemplos y teoría de fondo.
Roman

Respuestas:


76

Mejoremos el ejemplo del apilador y usemos las clases de casos de Scala :

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

La clase de Scala anterior contiene todas las características de la siguiente clase de Java y algunas más ; por ejemplo, admite la coincidencia de patrones (que Java no tiene). Scala 2.8 agrega argumentos con nombre y predeterminados, que se utilizan para generar un método de copia para clases de casos, que brinda la misma capacidad que los métodos with * de la siguiente clase Java.

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

Entonces, en uso tenemos (por supuesto):

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

En contra

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

2
En 2.7.xy 2.8.0, el único boxing está en productElementsy unapply, no en el constructor, campo o acceso: gist.github.com/424375
retronym

2
Fomenta todo tipo de maldades getter / setter. Los incubadores solo deben agregarse con extrema desgana, los captadores solo deben agregarse si es necesario. Buen ejemplo de cómo agregar "Simplicidad" conduce a malos hábitos.
Bill K

7
@Bill K: OK, entonces tendremos ¿ case class Person(val firstName: String, val lastName: String) Y qué? Hacer que esa cosa sea privada también sería posible, pero no tiene ningún sentido, debido a que no se aplica, etc.
soc

1
@shiva case class Person(private val firstName: String), pero entonces no deberías usar clases de casos. En su lugar hacer class Person(firstName: String)y firstNameque es privado de forma predeterminada.
nilskp

1
@shiva No. La diferencia entre valy private vales que si los métodos de acceso, es decir , firstName()y firstName(String), son públicos o privados. En Scala, los campos son siempre privados. Para que Scala genere métodos get / set de estilo Java (además de los accesores de estilo Scala), existe la @BeanPropertyanotación.
Esko Luontola

45

Encontré este impresionante

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)

Además de estos (perdón por no pegar, no quería robar el código)


Este código scala no generará métodos getFirstNamey getLastName. Tienes que anotar los parámetros con scala.reflect.BeanPropertyanotación para hacer eso.
Abhinav Sarkar

7
@ abhin4v: Sí, pero la convención de código en Scala es no tener accesos con el prefijo get. El código idiomático de Java es diferente del código idiomático de Scala. A veces, el isprefijo utilizado para booleanos. davetron5000.github.com/scala-style/naming_conventions/methods/…
Esko Luontola

6
Puede hacer eso case classy obtener el toString, equalsy hashCodegratis (y tampoco tiene que hacer los argumentos valexplícitamente):case class Person(firstName: String, lastName: String)
Jesper

@shiva, para case class, no solo class.
nilskp

23

Tarea: escriba un programa para indexar una lista de palabras clave (como libros).

Explicación:

  • Entrada: Lista <String>
  • Salida: Mapa <Carácter, Lista <String>>
  • La clave del mapa es 'A' a 'Z'
  • Cada lista del mapa está ordenada.

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

Puede utilizar v.sorted en lugar de (v sortBy identity).
Eastsun

1
Y con Scala 2.8, puede usar mapValues ​​(_.sorted) en lugar de map {case ...}
Alex Boisvert

10
Con Java 8, el código es casi idéntico a Scalas: keywords.stream (). Sorted (). Collect (Collectors.groupingBy (it -> it.charAt (0))); ¡Hace el truco!
The Coordinator

11

Tarea:

Tienes una lista peoplede objetos de clase Personque tiene campos namey age. Su tarea es ordenar esta lista primero por namey luego por 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))

Actualizar

Desde que escribí esta respuesta, ha habido bastante progreso. Las lambdas (y las referencias de métodos) finalmente aterrizaron en Java, y están tomando el mundo de Java por asalto.

Así es como se verá el código anterior con Java 8 (contribuido por @fredoverflow):

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

Si bien este código es casi tan corto, no funciona con tanta elegancia como el de Scala.

En la solución Scala, el Seq[A]#sortBymétodo acepta una función A => Bdonde Bse requiere tener un Ordering. Orderinges una clase de tipo. Piense lo mejor de ambos mundos: Comparablees implícito para el tipo en cuestión, pero Comparatores extensible y se puede agregar retrospectivamente a los tipos que no lo tenían. Dado que Java carece de clases de tipos, tiene que duplicar cada uno de esos métodos, una vez por Comparabley luego por Comparator. Por ejemplo, vea comparingy thenComparing aquí .

Las clases de tipos permiten escribir reglas como "Si A tiene orden y B tiene orden, entonces su tupla (A, B) también tiene orden". En código, eso es:

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

Así es como sortByen nuestro código se puede comparar por nombre y luego por edad. Esa semántica se codificará con la "regla" anterior. Un programador de Scala esperaría intuitivamente que esto funcionara de esta manera. No se comparingtuvo que agregar ningún método de propósito especial como Ordering.

Las lambdas y las referencias a métodos son solo la punta de un iceberg que es la programación funcional. :)


La falta de lambdas (o al menos las referencias a métodos) es la característica más importante que echo de menos en Java.
Petr Gladkikh

@fredoverflow Gracias por agregar el ejemplo de Java 8. Todavía demuestra por qué el enfoque de Scala es superior. Agregaré más más tarde.
missingfaktor

@rakemous, amigo, la respuesta fue escrita hace más de seis años.
missingfaktor

10

Tarea:

Tiene un archivo XML "company.xml" que se parece a esto:

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

Tienes que leer este archivo e imprimir los campos firstNamey lastNamede todos los empleados.


Java: [tomado de aquí ]

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: [tomado de aquí , diapositiva 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)
        } 
      }
    }
  }
}

[EDITAR por Bill; Verifique los comentarios para la discusión] -

Hmm, cómo hacerlo sin responder en una sección de respuesta sin formato ... Hmph. Supongo que editaré tu respuesta y te dejaré eliminarla si te molesta.

Así es como lo haría en Java con mejores bibliotecas:

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

Este es solo un truco rápido que no involucra magia y todos los componentes reutilizables. Si quisiera agregar algo de magia, podría hacer algo mejor que devolver una matriz de matrices de cadenas, pero incluso así, este GoodXMLLib sería completamente reutilizable. El primer parámetro de scanFor es la sección, todos los parámetros futuros serían los elementos a encontrar que son limitados, pero la interfaz podría mejorarse ligeramente para agregar múltiples niveles de coincidencia sin ningún problema real.

Admitiré que Java tiene un soporte de biblioteca bastante deficiente en general, pero vamos, comparar un uso horrible de la biblioteca XML de una década (?) De Java con una implementación basada en ser conciso simplemente no es justo, y está lejos a partir de una comparación de idiomas!


hmm, el ejemplo de Java sería más corto y más atractivo con un analizador SAX o StAX. Pero aún así, el de SCALA es realmente bueno
oluies

5
El código Java está escrito exactamente para analizar ese archivo XML en particular sin intentar reutilizarlo y con una gran cantidad de código duplicado. Quien lo escribió estaba tratando de parecer deliberadamente que no entendía codificación o que no entendía codificación.
Bill K

@Bill K: Nunca he hecho análisis XML en Java, así que elegí este ejemplo de algún sitio aleatorio. Siéntase libre de editar la parte de Java de la respuesta, no me importa.
missingfaktor

Bueno, supongamos que está hablando de diferencias de idioma y no de bibliotecas; en ese caso, los dos serían casi idénticos. La única diferencia de idioma en el segundo ejemplo es la coincidencia / caso que podría hacerse en una sola línea como un bucle for si la biblioteca lo implementa de esa manera.
Bill K

@Bill K: No, estás completamente equivocado. Hay dos funciones de Scala muy poderosas en juego aquí: 1. Literales XML 2. Coincidencia de patrones. Java no tiene ninguno de estos. Por lo tanto, el código Java equivalente escrito en alguna biblioteca hipotética seguramente NO será idéntico. (Intente escribir, lo sabrá.)
missingfaktor

10

Un mapa de acciones a realizar en función de una cadena.

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

¡Y todo está hecho con el mejor sabor posible!

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, creo que tu edición es incorrecta. todos.get("hi")devuelve lo Option[()=>Unit]que se necesita para coincidir correctamente.
huynhjl

@huynhjl, mi mal. Lo enrollo hacia atrás.
missingfaktor

3
Puede ser aún más corto:val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
Geoff Reedy

2
Aún más corto: val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }y luegotodos("hi")()
Martin Ring

8

Estoy escribiendo un juego de Blackjack en Scala ahora. Así es como se vería mi método dealerWins en Java:

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

Así es como se ve en Scala:

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

¡Hurra por las funciones de orden superior!

Solución Java 8:

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

scala tiene una sintaxis muy difícil. Necesito recordar mucho :-(
AZ_

Scala es como CSS, para recordar muchos atributos y propiedades
AZ_

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

7

Me gustó este simple ejemplo de clasificación y transformación, tomado del libro '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)

6

¿Qué tal Quicksort?


Java

El siguiente es un ejemplo de Java encontrado a través de una búsqueda de Google,

la URL es 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

Un intento rápido de una versión de Scala. Temporada abierta para mejoradores de código; @)

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
¿Esa clasificación rápida en listas vinculadas tiene una complejidad de tiempo O (n ^ 2) o no? Normalmente se utiliza mergesort o similar para listas enlazadas.
Esko Luontola

3
Tampoco es recursivo de cola y, por lo tanto, no es adecuado como algoritmo de rendimiento (o uno que no desbordará la pila)
oxbow_lakes

Gracias por los útiles comentarios. Había visto una clasificación rápida escrita como esta en alguna parte y me impresionó su tamaño compacto, claramente no le di mucha consideración. Me dejé llevar por la comparación LOC, que siempre es algo seductor con Scala v Java.
Don Mackenzie

2
Quicksort no es O (n ^ 2) en las listas funcionales, pero ciertamente tiene ese peligro. Asintóticamente, sigue siendo O (n log n) promedio , pero existe una mayor probabilidad estadística de alcanzar el peor de los casos O (n ^ 2) porque siempre seleccionamos el punto de pivote al principio de la lista, en lugar de elegir uno al azar. .
Daniel Spiewak

Filtrar dos veces es malo. Vea en mi respuesta a su pregunta el uso de partitionpara evitar eso.
Daniel C. Sobral

6

Me gustó tanto la respuesta del usuario desconocido que voy a intentar mejorarla. El código siguiente no es una traducción directa del ejemplo de Java, pero realiza la misma tarea con la misma 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)
}

No tengo scala-2.8 instalado por ahora, para probar este fragmento, pero creo que puedo ver lo que es intendet, solo que las 'palabras clave' no se usan en absoluto. Produce un mapa de todas las cuerdas y sus frecuencias, ¿no es así?
usuario desconocido

@user Sí, eso es lo que hace. ¿No es eso lo que logra tu código? Oh ya veo. Copié la línea incorrecta. Lo arreglaré ahora mismo. :-)
Daniel C. Sobral

6

Me gusta mucho el método getOrElseUpdate, que se encuentra en mutableMap y se muestra aquí, primero en Java, sin:

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

sí, un WordCount, y aquí 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
}

Y aquí está 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;
}

Y si quieres ir 100% funcional:

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

filtery sortya se han mostrado, pero mira lo fácil que se integran con el mapa:

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

Me gusta mucho este ejemplo. Evita la ruta fácil de comparar clases de casos y no comete el error de mostrar el código Scala y no el equivalente de Java.
Daniel C. Sobral

5

Este es un ejemplo muy simple: cuadrados enteros y luego sumarlos


    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)

El mapa compacto aplica la función a todos los elementos de la matriz, por lo que:

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

Doblar a la izquierda comenzará con 0 como acumulador (es) y se aplicará add(s,i)a todos los elementos (i) de la matriz, de modo que:

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

Ahora esto se puede compactar aún más para:

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

Este no lo probaré en Java (mucho trabajo), convertir XML en un mapa:


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

Otro trazador de líneas para obtener el mapa del 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)

El problema con tu sumSquareen Scala es que parece muy críptico para un desarrollador de Java, que les dará munición en tu contra para quejarse de que Scala es oscuro y complicado ...
Jesper

Reformateé un poco para mejorar el ejemplo. Espero que esto no perjudique a Scala.
Thomas

5
scala> 1 a 10 map (x => x * x) sum res0: Int = 385 Veamos al desarrollador de Java llamar a eso críptico. En ese momento, los dedos en los oídos dicen nah-nah-nah.
psp

3
@Jesper Para un desarrollador que no es Java, Java parece una gran cantidad de repetición y ruido de línea. Eso no significa que no puedas hacer un trabajo real en el idioma.
James Moore

Puede usar reduceLeft (agregar) en lugar de foldLeft (0) (agregar). Creo que es más fácil de leer cuando su elemento de inicio es el elemento cero / identidad del grupo.
Debilski

5

Problema: necesita diseñar un método que ejecute cualquier código dado de forma asincrónica.

Solución 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
            }
});

Lo mismo en Scala (usando actores):

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
A partir de 2.8, esto se puede escribir como Futures.future {cuerpo} y en realidad es más poderoso ya que el futuro devuelto por esto se puede unir para obtener el valor al que finalmente se evalúa.
Dave Griffith

3

El patrón de disyuntor de Release It de Michael Nygard en FaKods ( enlace al código )

La implementación se ve así en Scala:

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


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

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

Lo que creo que es super bonito. Parece una parte del lenguaje, pero es una simple combinación en el objeto CircuitBreaker que hace todo el trabajo.

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

Referencia en otros idiomas de Google para "Disyuntor" + su idioma.


3

Estoy preparando un documento que da varios ejemplos de código Java y Scala, utilizando solo las características simples de entender de Scala:

Scala: un Java mejor

Si desea que agregue algo, responda en los comentarios.


El título "Scala: un Java mejor" es engañoso
caza del pato

2

Por qué nadie publicó esto antes:

Java:

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

116 caracteres.

Scala:

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

56 caracteres.


1
Applicationrasgo considerado dañino ... scala-blogs.org/2008/07/…
missingfaktor

1

Los flujos infinitos evaluados con pereza son un buen ejemplo:

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

}

Aquí hay una pregunta que aborda flujos infinitos en Java: ¿Es un iterador infinito un mal diseño?

Otro buen ejemplo son las funciones y cierres de primera clase:

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 no admite funciones de primera clase y la imitación de cierres con clases internas anónimas no es muy elegante. Otra cosa que este ejemplo muestra que java no puede hacer es ejecutar código desde un intérprete / REPL. Encuentro esto inmensamente útil para probar rápidamente fragmentos de código.


Tenga en cuenta que el tamiz es demasiado lento para ser práctico.
Elazar Leibovich

@oxbow_lakes no hay un java equivalente para estos ejemplos.
dbyrne

@dbyme No es cierto. Puede subclasificar fácilmente Java Iterabley Iteratorproducir secuencias infinitas.
Daniel C. Sobral

@dbyrne "Otra cosa que muestra este ejemplo que Java no puede hacer es ejecutar código desde un intérprete / REPL. Encuentro esto inmensamente útil para probar rápidamente fragmentos de código". Utilizo una página de álbum de recortes en Eclipse para probar fragmentos de Java. Haciendo la mayoría, si no todo el trabajo de Java en ese IDE, no necesito REPL. Usé notepad.exe y javac en mis primeros días cuando no estaba seguro acerca de una característica de idioma o biblioteca y, después de un corto tiempo, todo fue muy bien y rápido, aunque un REPL es algo más fácil de usar y más rápido. Podría haber evitado el truco del bloc de notas por completo instalando VisualAge que ya teníamos en

0

Este código 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))
  })
}

... sería completamente ilegible en Java, si es posible.


10
MI CORRECTO OPINIO: ¡gracias por la respuesta! pero, ¿podría explicar qué sucede allí? Todavía no estoy familiarizado con la sintaxis de Scala, y (esa es la posible razón por la que) parece completamente ilegible incluso ahora para mí.
Roman

Está particionando una lista genérica de tipo T usando una función de partición proporcionada como protección en las cláusulas de coincidencia de patrones de la declaración del caso.
SÓLO MI OPINIÓN correcta

3
Extraño. No soy ni remotamente un experto en Scala y puedo resolver eso.
SOLO MI OPINIÓN correcta
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.