Amostras de código Scala e Java em que o código Scala parece mais simples / tem menos linhas?

94

Preciso de alguns exemplos de código (e também estou muito curioso sobre eles) de código Scala e Java que mostrem que o código Scala é mais simples e conciso do que o código escrito em Java (é claro que os dois exemplos devem resolver o mesmo problema).

Se houver apenas uma amostra de Scala com comentários como "isso é uma fábrica abstrata em Scala, em Java parecerá muito mais complicado", então também é aceitável.

Obrigado!

Eu gosto mais de tudo aceito e isso responde

romano
fonte
3
Com um pouco de trabalho, você pode encontrar muitas amostras em rosettacode.org
nicerobot
4
Como pode haver uma resposta correta neste tipo de pergunta?
poligenelubrificantes de
@polygenelubricants: e o que você sugere?
Romano
10
@Roman: Esperamos que o Scala seja mais conciso. Seria mais interessante se você pudesse encontrar algo que fosse expresso de forma mais concisa em Java do que em Scala.
Randall Schulz
1
@Randall Schulz: todo mundo sabe que Scala é mais conciso, mas às vezes, no propósito acadêmico, precisamos de uma prova com exemplos e teoria de fundo.
Romano

Respostas:

76

Vamos melhorar o exemplo do stacker e usar as classes de caso do Scala :

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

A classe Scala acima contém todos os recursos da classe Java abaixo e mais alguns - por exemplo, ela oferece suporte a correspondência de padrões (que o Java não tem). Scala 2.8 adiciona argumentos nomeados e padrão, que são usados ​​para gerar um método de cópia para classes de caso, o que oferece a mesma capacidade que os métodos with * da seguinte classe 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 + ")";
    }
}

Então, em uso, temos (é claro):

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

Contra

val mr = Person("Bob", "Dobbelina")
val miss = Person("Roberta", "MacSweeney")
val mrs = miss copy (lastName = mr.lastName)
Esko Luontola
fonte
2
Em 2.7.xe 2.8.0, o único boxe é dentro productElementse unapplynão no construtor, campo ou acessador: gist.github.com/424375
retrônimo de
2
Encoraja todos os tipos de maldade getter / setter. Os setters só devem ser adicionados com extrema relutância, os getters só devem ser adicionados se necessário. Bom exemplo de como adicionar "Simplicidade" leva a maus hábitos.
Bill K
7
@Bill K: OK, então teremos case class Person(val firstName: String, val lastName: String) E daí? Tornar essa coisa privada também seria possível, mas não faz sentido, por causa da não aplicação, etc.
soc
1
@shiva case class Person(private val firstName: String), mas você não deveria usar classes de caso então. Em vez disso, faça class Person(firstName: String)e firstNameé privado por padrão.
nilskp
1
@shiva Não. A diferença entre vale private valé que se os métodos de acesso, isto é , firstName()e firstName(String), são públicos ou privados. No Scala, os campos são sempre privados. Para que o Scala gere métodos get / set no estilo Java (além dos acessores no estilo Scala), existe a @BeanPropertyanotação.
Esko Luontola de
45

Eu achei este impressionante

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)

Bem como estes (desculpe por não colar, eu não queria roubar o código)

empilhador
fonte
Este código scala não gerará métodos getFirstNamee getLastName. Você tem que anotar os parâmetros com scala.reflect.BeanPropertyanotações para fazer isso.
Abhinav Sarkar
7
@ abhin4v: Sim, mas a convenção de código no Scala é não ter acessores prefixados com get. O código idiomático Java é diferente do código idiomático Scala. Às vezes, o isprefixo usado para booleanos. davetron5000.github.com/scala-style/naming_conventions/methods/…
Esko Luontola
6
Você poderia fazer isso a case classe obter o toString, equalse hashCodede graça (e também não precisa apresentar os argumentos valexplicitamente):case class Person(firstName: String, lastName: String)
Jesper
@shiva, para case class, não apenas class.
nilskp
23

Tarefa: Escreva um programa para indexar uma lista de palavras-chave (como livros).

Explicação:

  • Entrada: Lista <>
  • Saída: Map <Character, List <String>>
  • A chave do mapa é de 'A' a 'Z'
  • Cada lista no mapa é classificada.

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)
}
faltando faktor
fonte
Você pode usar v.sorted em vez de (v sortBy identity).
Eastsun
1
E com Scala 2.8, você pode usar mapValues ​​(_.sorted) em vez de map {case ...}
Alex Boisvert
10
Com o Java 8, o código é quase idêntico ao Scalas: keywords.stream (). Sorted (). Collect (Collectors.groupingBy (it -> it.charAt (0))); faz o truque!
O Coordenador de
11

Tarefa:

Você tem uma lista peoplede objetos de classe Personque contém os campos namee age. Sua tarefa é classificar essa lista primeiro por namee depois 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))

Atualizar

Desde que escrevi esta resposta, houve algum progresso. Os lambdas (e as referências de método) finalmente chegaram ao Java e estão conquistando o mundo Java.

Esta é a aparência do código acima com Java 8 (contribuição de @fredoverflow):

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

Embora esse código seja quase tão curto, ele não funciona tão elegantemente quanto o do Scala.

Na solução Scala, o Seq[A]#sortBymétodo aceita uma função A => Bonde Bé necessário ter um Ordering. Orderingé uma classe-tipo. Pense melhor nos dois mundos: tipo Comparable, é implícito para o tipo em questão, mas tipo Comparator, é extensível e pode ser adicionado retrospectivamente a tipos que não o tinham. Como Java não possui classes de tipo, ele deve duplicar cada um desses métodos, uma vez para Comparable, depois para Comparator. Por exemplo, veja comparinge thenComparing aqui .

As classes de tipo permitem escrever regras como "Se A tem ordenação e B tem ordenação, então sua tupla (A, B) também tem ordenação". Em código, isto é:

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

É assim que o sortByem nosso código pode ser comparado por nome e depois por idade. Essas semânticas serão codificadas com a "regra" acima. Um programador de Scala intuitivamente espera que isso funcione dessa maneira. Nenhum método de propósito especial como comparingteve que ser adicionado Ordering.

Lambdas e referências de método são apenas a ponta de um iceberg que é a programação funcional. :)

faltando faktor
fonte
Lambdas ausentes (ou pelo menos referências de método) é o recurso mais importante que sinto falta em Java.
Petr Gladkikh
@fredoverflow Obrigado por adicionar o exemplo Java 8. Ele ainda demonstra porque a abordagem do Scala é superior. Vou adicionar mais tarde.
missingfaktor
@rakemous, companheiro, a resposta foi escrita há mais de seis anos.
missingfaktor
10

Tarefa:

Você tem um arquivo XML "empresa.xml" que se parece com este:

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

Você deve ler este arquivo e imprimir os campos firstNamee lastNamede todos os funcionários.


Java: [tirado daqui ]

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: [tirado daqui , slide # 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)
        } 
      }
    }
  }
}

[EDIT por Bill; Verifique os comentários da discussão] -

Hmm, como fazer isso sem responder em uma seção de resposta não formatada ... Hmph. Acho que vou editar sua resposta e deixar você excluí-la se incomodar.

É assim que eu faria em Java com melhores 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 é apenas um hack rápido que envolve nenhuma magia e todos os componentes reutilizáveis. Se eu quisesse adicionar um pouco de mágica, poderia fazer algo melhor do que retornar uma matriz de matrizes de string, mas mesmo assim, GoodXMLLib seria completamente reutilizável. O primeiro parâmetro de scanFor é a seção, todos os parâmetros futuros seriam os itens a serem encontrados, o que é limitado, mas a interface poderia ser ligeiramente aprimorada para adicionar vários níveis de correspondência sem nenhum problema real.

Admito que o Java tem um suporte de biblioteca muito pobre em geral, mas vamos lá - comparar um uso horrível da biblioteca XML de uma década (?) De Java com uma implementação feita com base em ser conciso não é justo - e está longe a partir de uma comparação das línguas!

faltando faktor
fonte
hmm, o exemplo Java seria mais curto e mais bonito com um analisador SAX ou StAX. Mas ainda assim o SCALA é muito bom
oluies
5
O código Java é escrito exatamente para analisar esse arquivo XML específico, sem nenhuma tentativa de reutilização e com muito código duplicado. Quem quer que o tenha escrito estava tentando deliberadamente parecer que não entendia de codificação ou não entendia de codificação.
Bill K
@Bill K: Nunca fiz análise de XML em Java, então escolhi este exemplo de algum site aleatório. Sinta-se à vontade para editar a parte Java da resposta, não me importo.
missingfaktor
Bem, vamos supor que você esteja falando sobre diferenças de idioma e não diferenças de biblioteca - nesse caso, os dois seriam quase idênticos. A única diferença de linguagem no segundo exemplo é o match / case que poderia ser feito em uma única linha como um loop for se implementado dessa forma pela biblioteca.
Bill K
@Bill K: Não, você está completamente errado. Existem dois recursos Scala muito poderosos em ação aqui: 1. Literais XML 2. Correspondência de padrões. Java não tem nenhum desses. Portanto, o código Java equivalente escrito em alguma biblioteca hipotética certamente NÃO será idêntico. (Tente escrever, você saberá.)
missingfaktor
10

Um mapa de ações a serem executadas dependendo de uma string.

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

E tudo com o melhor gosto possível!

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();
Ben Hardy
fonte
@Rahul G, acho que sua edição está incorreta. todos.get("hi")retorna Option[()=>Unit]que é necessário para corresponder corretamente.
Huynhjl
@huynhjl, que pena. Revertido.
missingfaktor
3
Pode ser ainda mais curto:val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
Geoff Reedy
2
Ainda mais curto: val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }e entãotodos("hi")()
Martin Ring
8

Estou escrevendo um jogo de Blackjack no Scala agora. Aqui está como meu método dealerWins ficaria em Java:

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

Veja como fica no Scala:

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

Viva as funções de ordem superior!

Solução Java 8:

boolean dealerWins() {
    return players.stream().noneMatch(player -> player.beats(dealer));
}
MikeFHay
fonte
scala tem uma sintaxe muito difícil. preciso lembrar tanto :-(
AZ_
Scala é como CSS, com muitos atributos e propriedades a serem lembrados
AZ_
1
melhor:def dealerWins = !(players exists (_ beats dealer))
Kevin Wright
7

Gostei deste exemplo simples de classificação e transformação, tirado do livro 'Beginning Scala' de David Pollak:

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

Em 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)
Arjan Blokzijl
fonte
6

Que tal Quicksort?


Java

A seguir está um exemplo de java encontrado por meio de uma pesquisa no Google,

o URL é 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

Uma tentativa rápida de uma versão Scala. Temporada de caça para melhoradores 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))
  }
}
Don Mackenzie
fonte
1
Essa classificação rápida em listas vinculadas tem complexidade de tempo O (n ^ 2) ou não? Normalmente, mergesort ou similar é usado para listas vinculadas.
Esko Luontola
3
Também não é recursivo na cauda e, portanto, inadequado como um algoritmo de desempenho (ou um que não irá
estourar
Obrigado pelos comentários úteis. Eu tinha visto quicksort escrito assim em algum lugar e fiquei impressionado com sua compactação, claramente não dei muita atenção a isso. Eu me empolguei com a comparação LOC, que é sempre uma coisa sedutora com Scala v Java.
Don Mackenzie
2
Quicksort não é O (n ^ 2) em listas funcionais, mas certamente tem esse perigo. Assintoticamente, ainda é O médio (n log n) , mas há uma probabilidade estatística maior de acertar o pior caso O (n ^ 2) porque sempre selecionamos o ponto de pivô no início da lista, em vez de escolher um aleatoriamente .
Daniel Spiewak
Filtrar duas vezes é ruim. Veja na minha resposta à sua pergunta o uso de partitionpara evitar isso.
Daniel C. Sobral
6

Gostei tanto da resposta do usuário desconhecido que vou tentar melhorá-la. O código a seguir não é uma tradução direta do exemplo Java, mas realiza a mesma tarefa com a mesma 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)
}
Daniel C. Sobral
fonte
Eu não tenho o scala-2.8 instalado agora, para testar este snippet, mas acho que posso ver o que é intendet - apenas 'palavras-chave' não são usadas. Ele produz um mapa de todas as cordas e suas frequências, não é?
usuário desconhecido
@user Sim, é isso que faz. Não é isso que o seu código consegue? Ah eu vejo. Copiei a linha errada. Eu vou consertar isso agora. :-)
Daniel C. Sobral
6

Gosto muito do método getOrElseUpdate, encontrado em mutableMap e mostrado aqui, primeiro Java, sem:

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

sim - um WordCount, e aqui no 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
}

E aqui está em 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;
}

E se você quiser ficar 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);
}

filtere sortjá foram mostrados, mas veja como são fáceis de integrar com o 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)
    } 
Usuário desconhecido
fonte
Eu gosto muito deste exemplo. Isso evita a rota fácil de comparar classes de caso e não comete o erro de mostrar o código Scala e não o equivalente Java.
Daniel C. Sobral
5

Este é um exemplo muito simples: inteiros quadrados e, em seguida, adicione-os


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

Em escala:


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)

O mapa compacto aplica a função a todos os elementos da matriz, portanto:

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

A dobra para a esquerda começará com 0 como o (s) acumulador (es) e se aplicará add(s,i)a todos os elementos (i) da matriz, de modo que:

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

Agora, isso pode ser ainda mais compactado para:

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

Este eu não vou tentar em Java (dá muito trabalho), transforme XML em um mapa:


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

Outra linha para obter o mapa do 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)
Thomas
fonte
O problema com o seu sumSquareno Scala é que ele parece muito enigmático para um desenvolvedor Java, que lhes dará munição contra você para reclamar que o Scala é obscuro e complicado ...
Jesper
Reformatei um pouco para melhorar o exemplo. Espero que isso não prejudique Scala.
Thomas
5
scala> 1 a 10 map (x => x * x) sum res0: Int = 385 Vamos ver o desenvolvedor Java chamar isso de enigmático. Nesse ponto, são os dedos nas orelhas dizendo nah-nah-nah.
PSP
3
@Jesper Para um desenvolvedor não Java, Java parece uma grande quantidade de clichês e ruído de linha. Isso não significa que você não possa realizar um trabalho de verdade no idioma.
James Moore
Você poderia usar reduceLeft (add) em vez de foldLeft (0) (add). Acho que é mais fácil de ler quando o elemento inicial é o elemento zero / identidade do grupo.
Debilski
5

Problema: você precisa projetar um método que execute qualquer código fornecido de forma assíncrona.

Solução em 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
            }
});

A mesma coisa em Scala (usando atores):

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    
}
Vasil Remeniuk
fonte
6
A partir de 2.8, isso pode ser escrito como Futures.future {body} e é realmente mais poderoso, pois o futuro retornado por isso pode ser unido para obter o valor que ele eventualmente avalia.
Dave Griffith
3

O padrão do disjuntor do Release It in FaKods de Michael Nygard ( link para o código )

implementação se parece com isto no Scala:

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


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

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

O que eu acho super legal. Parece apenas uma amostra da linguagem, mas é um mixin simples no objeto CircuitBreaker fazendo todo o trabalho.

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

Referência em outros idiomas Google para "Disjuntor" + seu idioma.

oluies
fonte
3

Estou preparando um documento que fornece vários exemplos de código Java e Scala, utilizando apenas os recursos simples de entender do Scala:

Scala: um Java melhor

Se você gostaria que eu acrescentasse algo, por favor responda nos comentários.

HRJ
fonte
Título "Scala: A better Java"
engana
2

Por que ninguém postou isso 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.

OscarRyz
fonte
1
Applicationtraço considerado prejudicial ... scala-blogs.org/2008/07/…
missingfaktor
1

Streams infinitos avaliados lentamente são um bom exemplo:

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

}

Aqui está uma questão que trata de fluxos infinitos em Java: Um iterador infinito é um projeto ruim?

Outro bom exemplo são funções de primeira classe e encerramentos:

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 não suporta funções de primeira classe e imitar fechamentos com classes internas anônimas não é muito elegante. Outra coisa que este exemplo mostra que o java não pode fazer é executar o código de um interpretador / REPL. Acho isso extremamente útil para testar trechos de código rapidamente.

dbyrne
fonte
Observe que a peneira é muito lenta para ser prática.
Elazar Leibovich
@oxbow_lakes não há java equivalente para esses exemplos.
dbyrne
@dbyme Não é verdade. Você pode facilmente criar uma subclasse de Java Iterablee Iteratorproduzir fluxos infinitos.
Daniel C. Sobral
@dbyrne "Outra coisa que este exemplo mostra que o java não pode fazer é executar código de um interpretador / REPL. Acho isso extremamente útil para testar trechos de código rapidamente." Eu uso uma página de scrapbook no Eclipse para experimentar trechos de Java. Fazendo a maioria, senão todo o trabalho Java nesse IDE, não preciso de REPL. Eu usei notepad.exe e javac nos meus primeiros dias quando não tinha certeza sobre um recurso de linguagem ou biblioteca e depois de um curto período de tempo funcionou muito bem e rápido - embora um REPL seja um pouco mais fácil de usar - e mais rápido. Eu poderia ter evitado o hack do notepad completamente instalando o VisualAge que já tínhamos
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))
  })
}

... seria completamente ilegível em Java, se possível.

APENAS MINHA OPINIÃO correta
fonte
10
MEU OPINIO correto: obrigado pela resposta! mas você poderia explicar o que acontece lá? Não estou familiarizado com a sintaxe do Scala ainda e (essa é a possível razão) ela parece completamente ilegível até agora para mim.
Romano
Ele está particionando uma lista genérica do tipo T usando uma função de particionamento fornecida como um guarda nas cláusulas de correspondência de padrões da instrução case.
APENAS MINHA OPINIÃO correta
3
Esquisito. Não sou nem remotamente um especialista em Scala e posso descobrir isso.
APENAS MINHA OPINIÃO correta