Contoh kode Scala dan Java di mana kode Scala terlihat lebih sederhana / memiliki lebih sedikit baris?

94

Saya memerlukan beberapa contoh kode (dan saya juga sangat ingin tahu tentang mereka) dari kode Scala dan Java yang menunjukkan bahwa kode Scala lebih sederhana dan ringkas daripada kode yang ditulis di Java (tentu saja kedua contoh harus menyelesaikan masalah yang sama).

Jika hanya ada sampel Scala dengan komentar seperti "ini adalah pabrik abstrak di Scala, di Java akan terlihat jauh lebih rumit" maka ini juga dapat diterima.

Terima kasih!

Saya suka hampir semua diterima dan jawaban ini

Roma
sumber
3
Dengan sedikit kerja kaki, Anda mungkin menemukan banyak sampel di rosettacode.org
nicerobot
4
Bagaimana bisa ada satu jawaban yang benar untuk pertanyaan semacam ini?
poligenelubricants
@ polygenelubricants: dan apa yang Anda sarankan?
Roman
10
@ Roma: Kami berharap Scala lebih ringkas. Akan lebih menarik jika Anda bisa menemukan sesuatu yang diekspresikan dengan lebih ringkas di Jawa daripada di Scala.
Randall Schulz
1
@Randall Schulz: semua orang tahu bahwa Scala lebih ringkas, tapi terkadang, dalam tujuan akademis, kita membutuhkan bukti dengan contoh dan teori latar belakang.
Roman

Jawaban:

76

Mari perbaiki contoh stacker dan gunakan kelas kasus Scala :

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

Kelas Scala di atas berisi semua fitur dari kelas Java di bawah, dan beberapa lagi - misalnya mendukung pencocokan pola (yang tidak dimiliki Java). Scala 2.8 menambahkan argumen bernama dan default, yang digunakan untuk menghasilkan metode salin untuk kelas kasus, yang memberikan kemampuan yang sama seperti metode with * dari kelas Java berikut.

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

Kemudian, dalam penggunaan kami memiliki (tentu saja):

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

Melawan

val mr = Person("Bob", "Dobbelina")
val miss = Person("Roberta", "MacSweeney")
val mrs = miss copy (lastName = mr.lastName)
Esko Luontola
sumber
2
Di 2.7.x dan 2.8.0, satu-satunya tinju adalah productElementsdan unapply, bukan di konstruktor, bidang, atau pengakses
retronym
2
Mendorong segala jenis kejahatan pengambil / penyetel. Setter hanya boleh ditambahkan dengan keengganan yang ekstrim, pengambil harus ditambahkan hanya jika perlu. Contoh bagus tentang bagaimana menambahkan "Kesederhanaan" mengarah pada kebiasaan buruk.
Bill K
7
@Bill K: Oke, lalu kita akan punya case class Person(val firstName: String, val lastName: String) Jadi apa? Menjadikan hal itu pribadi juga mungkin, tetapi tidak masuk akal, karena tidak berlaku, dll.
soc
1
@shiva case class Person(private val firstName: String), tetapi Anda seharusnya tidak menggunakan kelas kasus. Sebaliknya lakukan class Person(firstName: String)dan firstNamebersifat pribadi secara default.
nilskp
1
@shiva Tidak. Perbedaan antara valdan private valadalah apakah metode pengakses , yaitu firstName()dan firstName(String), bersifat publik atau privat. Di bidang Scala selalu bersifat pribadi. Agar Scala menghasilkan metode get / set gaya Java (selain pengakses gaya Scala), ada @BeanPropertyanotasi.
Esko Luontola
45

Saya menemukan yang ini mengesankan

Jawa

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)

Serta yang ini (maaf karena tidak menempel, saya tidak ingin mencuri kodenya)

stacker
sumber
Kode skala ini tidak akan menghasilkan getFirstNamedan getLastNamemetode. Anda harus membuat anotasi parameter dengan scala.reflect.BeanPropertyanotasi untuk melakukannya.
Abhinav Sarkar
7
@ abhin4v: Ya, tetapi konvensi kode di Scala adalah tidak memiliki pengakses yang diawali dengan get. Kode Java idiomatik berbeda dari kode Scala idiomatik. Terkadang isawalan digunakan untuk boolean. davetron5000.github.com/scala-style/naming_conventions/methods/…
Esko Luontola
7
Anda dapat membuatnya case classdan mendapatkan toString, equalsdan hashCodegratis (dan Anda juga tidak perlu membuat argumen valsecara eksplisit):case class Person(firstName: String, lastName: String)
Jesper
@shiva, untuk case class, bukan hanya untuk class.
nilskp
23

Tugas: Menulis program untuk mengindeks daftar kata kunci (seperti buku).

Penjelasan:

  • Input: Daftar <String>
  • Output: Peta <Karakter, Daftar <String>>
  • Kunci peta adalah 'A' sampai 'Z'
  • Setiap daftar di peta diurutkan.

Jawa:

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)
}
missingfaktor
sumber
Anda dapat menggunakan v.sorted daripada (v sortBy identity).
Eastsun
1
Dan dengan Scala 2.8, Anda dapat menggunakan mapValues ​​(_.sorted) daripada map {case ...}
Alex Boisvert
10
Dengan Java 8, kodenya hampir identik dengan Scalas: keywords.stream (). Sort (). Collect (Collectors.groupingBy (it -> it.charAt (0))); berhasil!
Koordinator
11

Tugas:

Anda memiliki daftar peopleobjek kelas Personyang memiliki bidang namedan age. Tugas Anda adalah mengurutkan daftar ini terlebih dahulu name, lalu menurutage .

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

Memperbarui

Sejak saya menulis jawaban ini, ada kemajuan yang cukup pesat. Lambda (dan referensi metode) akhirnya mendarat di Jawa, dan mereka menggemparkan dunia Jawa.

Seperti inilah kode di atas akan terlihat dengan Java 8 (disumbangkan oleh @fredoverflow):

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

Meskipun kode ini hampir sama pendeknya, kode ini tidak berfungsi dengan elegan seperti kode Scala.

Dalam larutan Scala, yang Seq[A]#sortBymetode menerima fungsi A => Bdi mana Bdiperlukan untuk memiliki sebuah Ordering. Orderingadalah kelas tipe. Pikirkan yang terbaik dari kedua dunia: Seperti Comparable, ini tersirat untuk jenis yang dimaksud, tetapi seperti Comparator, ini dapat diperluas dan dapat ditambahkan secara retrospektif ke jenis yang tidak memilikinya. Karena Java tidak memiliki kelas tipe, ia harus menduplikasi setiap metode tersebut, sekali untuk Comparable, lalu untuk Comparator. Misalnya, lihat comparingdan di thenComparing sini .

Kelas-tipe memungkinkan seseorang untuk menulis aturan seperti "Jika A memiliki pengurutan dan B memiliki pengurutan, maka tupelnya (A, B) juga memiliki pengurutan". Dalam kode, yaitu:

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

Begitulah cara sortBydalam kode kita dapat dibandingkan berdasarkan nama dan kemudian berdasarkan usia. Semantik tersebut akan dikodekan dengan "aturan" di atas. Seorang programmer Scala secara intuitif akan mengharapkan ini bekerja dengan cara ini. Tidak ada metode tujuan khusus seperti yang comparingharus ditambahkan Ordering.

Lambda dan referensi metode hanyalah puncak gunung es yang merupakan pemrograman fungsional. :)

missingfaktor
sumber
Lambda yang hilang (atau setidaknya referensi metode) adalah fitur terpenting yang saya lewatkan di Java.
Petr Gladkikh
@fredoverflow Terima kasih telah menambahkan contoh Java 8. Itu masih menunjukkan mengapa pendekatan Scala lebih unggul. Saya akan menambahkan lebih banyak nanti.
missingfaktor
@rakemous, sobat, jawabannya sudah ditulis lebih dari enam tahun yang lalu.
missingfaktor
10

Tugas:

Anda punya file XML "company.xml" yang terlihat seperti ini:

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

Anda harus membaca file ini dan mencetak bidang firstNamedan lastNamedari semua karyawan.


Jawa: [diambil dari sini ]

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: [diambil dari sini , 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 oleh Bill; Periksa komentar untuk diskusi] -

Hmm, bagaimana melakukannya tanpa membalas di bagian balasan yang tidak diformat ... Hmph. Saya kira saya akan mengedit jawaban Anda dan membiarkan Anda menghapusnya jika itu mengganggu Anda.

Beginilah cara saya melakukannya di Java dengan perpustakaan yang lebih baik:

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

Ini hanyalah peretasan cepat yang tidak melibatkan sihir dan semua komponen yang dapat digunakan kembali. Jika saya ingin menambahkan beberapa keajaiban saya bisa melakukan sesuatu yang lebih baik daripada mengembalikan array array string, tetapi bahkan seperti ini GoodXMLLib akan sepenuhnya dapat digunakan kembali. Parameter pertama dari scanFor adalah bagian, semua parameter yang akan datang adalah item yang akan ditemukan yang terbatas, tetapi antarmuka dapat digosok sedikit untuk menambahkan beberapa tingkat pencocokan tanpa masalah nyata.

Saya akan mengakui bahwa Java memiliki beberapa dukungan perpustakaan yang cukup buruk secara umum, tetapi ayolah - untuk membandingkan penggunaan yang mengerikan dari perpustakaan XML lama (?) Java dekade untuk implementasi yang dilakukan berdasarkan singkat tidak adil - dan jauh dari perbandingan bahasa!

missingfaktor
sumber
hmm, contoh Java akan menjadi lebih pendek dan lebih baik dengan parser SAX atau StAX. Tapi tetap saja SCALA yang sangat bagus
oluies
5
Kode Java ditulis persis untuk mengurai file XML tertentu tanpa upaya untuk menggunakan kembali dan banyak kode duplikat. Siapa pun yang menulisnya entah berusaha dengan sengaja terlihat seperti dia tidak mengerti coding atau tidak mengerti coding.
Bill K
@Bill K: Saya belum pernah melakukan parsing XML di Java jadi saya memilih contoh ini dari beberapa situs acak. Jangan ragu untuk mengedit bagian Java dari jawabannya, saya tidak keberatan.
missingfaktor
Mari kita asumsikan bahwa Anda berbicara tentang perbedaan bahasa dan bukan perbedaan perpustakaan - dalam hal ini, keduanya akan hampir identik. Satu-satunya perbedaan bahasa pada contoh kedua adalah hal match / case yang bisa dilakukan dalam satu baris sebagai loop for jika diimplementasikan dengan cara itu oleh library.
Bill K
@Bill K: Tidak, Anda sepenuhnya salah. Ada dua fitur Scala yang sangat kuat yang bekerja di sini: 1. Literal XML 2. Pencocokan Pola. Java tidak memiliki salah satu dari ini. Jadi kode Java yang setara yang ditulis di beberapa pustaka hipotetis pasti TIDAK identik. (Coba tulis, Anda akan tahu.)
missingfaktor
10

Peta tindakan yang harus dilakukan bergantung pada string.

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

Dan itu semua dilakukan dengan rasa terbaik!

Jawa 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
sumber
@Rahul G, menurut saya hasil edit Anda salah. todos.get("hi")kembali Option[()=>Unit]yang diperlukan untuk mencocokkan dengan benar.
huynhjl
@huynhjl, Saya buruk. Gulung kembali.
missingfaktor
3
Bisa lebih pendek lagi:val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
Geoff Reedy
2
Bahkan lebih pendek: val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }dan kemudiantodos("hi")()
Martin Ring
8

Saya sedang menulis game Blackjack di Scala sekarang. Berikut adalah tampilan metode dealerWins saya di Java:

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

Berikut tampilannya di Scala:

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

Hore untuk fungsi tingkat tinggi!

Solusi Java 8:

boolean dealerWins() {
    return players.stream().noneMatch(player -> player.beats(dealer));
}
MikeFHay
sumber
scala memiliki sintaks yang sangat sulit. sangat perlu diingat :-(
AZ_
Scala seperti CSS, dengan banyak atribut dan properti yang perlu diingat
AZ_
1
lebih baik:def dealerWins = !(players exists (_ beats dealer))
Kevin Wright
7

Saya menyukai contoh sederhana dari penyortiran dan transformasi ini, yang diambil dari buku 'Scala Awal' David Pollak:

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

Di Jawa:

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
sumber
6

Bagaimana dengan Quicksort?


Jawa

Berikut adalah contoh java yang ditemukan melalui pencarian google,

URL-nya adalah 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

Upaya cepat pada versi Scala. Musim terbuka untuk pemodifikasi kode; @)

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
sumber
1
Apakah quicksort pada daftar tertaut itu memiliki kompleksitas waktu O (n ^ 2) atau tidak? Biasanya mergesort atau serupa digunakan untuk daftar tertaut.
Esko Luontola
3
Ini juga tidak rekursif ekor dan karenanya tidak cocok sebagai algoritma yang berkinerja (atau yang tidak akan meluap-luap tumpukan)
oxbow_lakes
Terima kasih atas komentar yang bermanfaat. Saya pernah melihat quicksort ditulis seperti ini di suatu tempat dan terkesan dengan kekompakannya, jelas saya tidak terlalu mempertimbangkannya. Saya terbawa oleh perbandingan LOC, yang selalu merupakan hal yang menggoda dengan Scala v Java.
Don Mackenzie
2
Quicksort bukan O (n ^ 2) pada daftar fungsional, tetapi jelas memiliki bahaya itu. Secara asimtotik, ini masih rata-rata O (n log n) , tetapi ada probabilitas statistik yang lebih tinggi untuk mencapai kasus terburuk O (n ^ 2) karena kami selalu memilih titik pivot di bagian atas daftar, daripada memilihnya secara acak .
Daniel Spiewak
Memfilter dua kali itu buruk. Lihat dalam jawaban saya atas pertanyaan Anda penggunaan partitionuntuk menghindari itu.
Daniel C. Sobral
6

Saya sangat menyukai jawaban pengguna yang tidak diketahui sehingga saya akan mencoba memperbaikinya. Kode di bawah ini bukan terjemahan langsung dari contoh Java, tetapi menyelesaikan tugas yang sama dengan API yang sama.

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
sumber
Saya belum memasang scala-2.8 sekarang, untuk menguji cuplikan ini, tapi saya rasa saya bisa melihat apa itu intendet - hanya 'kata kunci' yang tidak digunakan sama sekali. Ini menghasilkan peta semua String dan frekuensinya, bukan?
pengguna tidak dikenal
@pengguna Ya, itulah yang dilakukannya. Bukankah itu yang dicapai oleh kode Anda? Oh begitu. Saya menyalin baris yang salah. Saya akan memperbaikinya sekarang. :-)
Daniel C. Sobral
6

Saya sangat menyukai metode getOrElseUpdate, ditemukan di mutableMap dan ditampilkan di sini, Java pertama, tanpa:

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

ya - WordCount, dan di sini dalam skala:

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
}

Dan ini dia di 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;
}

Dan jika Anda ingin 100% berfungsi:

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

filterdan sorttelah ditampilkan, tapi lihat betapa mudahnya mereka diintegrasikan dengan peta:

    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)
    } 
Pengguna tidak diketahui
sumber
Saya sangat menyukai contoh ini. Ini menghindari cara mudah untuk membandingkan kelas kasus, dan tidak membuat kesalahan dengan menampilkan kode Scala dan bukan Java yang setara.
Daniel C. Sobral
5

Ini adalah contoh yang sangat sederhana: Bilangan bulat persegi dan kemudian tambahkan


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

Dalam skala:


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)

Peta ringkas menerapkan fungsi ke semua elemen larik, jadi:

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

Lipat kiri akan dimulai dengan 0 sebagai akumulator dan berlaku add(s,i)untuk semua elemen (i) dari array, sehingga:

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

Sekarang ini dapat lebih dipadatkan menjadi:

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

Yang ini saya tidak akan mencoba di Java (untuk banyak pekerjaan), ubah XML menjadi Peta:


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

Satu liner lain untuk mendapatkan peta dari 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
sumber
Masalah dengan sumSquareScala Anda adalah bahwa itu terlihat sangat samar bagi pengembang Java, yang akan memberi mereka amunisi terhadap Anda untuk mengeluh bahwa Scala tidak jelas dan rumit ...
Jesper
Saya memformat ulang sedikit untuk meningkatkan contoh. Semoga ini tidak melukai Scala.
Thomas
5
scala> 1 to 10 map (x => x * x) sum res0: Int = 385 Mari kita lihat pengembang java menyebutnya samar. Pada saat itu jari-jari di telinga mengatakan nah-nah-nah.
psp
3
@Jesper Bagi pengembang non-Java, Java terlihat seperti boilerplate dan gangguan saluran dalam jumlah besar. Itu tidak berarti Anda tidak bisa menyelesaikan pekerjaan nyata dalam bahasa tersebut.
James Moore
Anda bisa menggunakan reduceLeft (add) daripada foldLeft (0) (add). Saya pikir lebih mudah dibaca ketika elemen awal Anda adalah elemen nol / identitas grup.
Debilski
5

Masalah: Anda perlu merancang metode yang akan mengeksekusi kode apa pun secara asinkron.

Solusi di Jawa :

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

Hal yang sama di Scala (menggunakan aktor):

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
sumber
6
Mulai 2.8, ini dapat ditulis sebagai Futures.future {body} dan sebenarnya lebih kuat karena masa depan yang dikembalikan oleh ini dapat digabungkan untuk mendapatkan nilai yang akhirnya dievaluasi.
Dave Griffith
3

Pola Pemutus Sirkuit dari Michael Nygard's Release It di FaKods ( tautan ke kode )

implementasi terlihat seperti ini di Scala:

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


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

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

Yang menurut saya sangat bagus. Ini terlihat hanya sebagai bagian dari bahasa tetapi ini adalah campuran sederhana di Object CircuitBreaker yang melakukan semua pekerjaan.

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

Referensi dalam bahasa lain Google untuk "Pemutus arus" + bahasa Anda.

oluies
sumber
3

Saya sedang menyiapkan dokumen yang memberikan beberapa contoh kode Java dan Scala, hanya memanfaatkan fitur Scala yang mudah dipahami:

Scala: Java yang lebih baik

Jika Anda ingin saya menambahkan sesuatu, silakan balas di komentar.

HRJ
sumber
Judul "Scala: A better Java" salah arah
duckhunt
2

Mengapa tidak ada yang memposting ini sebelumnya:

Jawa:

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

116 karakter.

Scala:

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

56 karakter.

OscarRyz
sumber
1
Applicationsifat yang dianggap berbahaya ... scala-blogs.org/2008/07/…
missingfaktor
1

Aliran tak terbatas yang dievaluasi dengan malas adalah contoh yang baik:

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

}

Berikut adalah pertanyaan untuk mengatasi aliran tak terbatas di Java: Apakah desain iterator tak terbatas buruk?

Contoh bagus lainnya adalah fungsi dan closure kelas satu:

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 tidak mendukung fungsi kelas satu, dan meniru closure dengan kelas dalam anonim tidak terlalu elegan. Hal lain yang ditunjukkan contoh ini yang tidak dapat dilakukan java adalah menjalankan kode dari interpreter / REPL. Saya merasa ini sangat berguna untuk menguji cuplikan kode dengan cepat.

dbyrne
sumber
Harap dicatat bahwa saringan terlalu lambat untuk praktis.
Elazar Leibovich
@oxbow_lakes tidak ada java yang setara untuk contoh ini.
dbyrne
@byme Tidak benar. Anda dapat dengan mudah membuat subkelas Java Iterabledan Iteratormenghasilkan aliran tak terbatas.
Daniel C. Sobral
@dbyrne "Hal lain yang ditunjukkan oleh contoh ini yang tidak dapat dilakukan java adalah menjalankan kode dari interpreter / REPL. Saya merasa ini sangat berguna untuk menguji cuplikan kode dengan cepat." Saya menggunakan halaman lembar memo di Eclipse untuk mencoba potongan Java. Melakukan sebagian besar, jika tidak semua Java berfungsi di IDE itu, saya tidak perlu REPL. Saya menggunakan notepad.exe dan javac di hari-hari awal saya ketika saya tidak yakin tentang fitur bahasa atau pustaka dan setelah waktu yang singkat berjalan dengan sangat baik dan cepat - meskipun REPL agak lebih mudah digunakan - dan lebih cepat. Saya bisa menghindari peretasan notepad sama sekali dengan menginstal VisualAge yang sudah kami miliki
0

Kode Scala ini ...

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

... akan benar-benar tidak terbaca di Java, jika memungkinkan.

HANYA PENDAPAT SAYA yang benar
sumber
10
OPINIO SAYA yang benar: terima kasih atas jawabannya! tetapi bisakah Anda menjelaskan apa yang terjadi di sana? Saya belum terbiasa dengan sintaks Scala, dan (itulah alasan yang mungkin mengapa) terlihat sama sekali tidak dapat dibaca bahkan untuk saya sekarang.
Roman
Ini mempartisi daftar generik tipe T menggunakan fungsi partisi yang disediakan sebagai penjaga dalam klausa pencocokan pola dari pernyataan kasus.
HANYA PENDAPAT SAYA yang benar
3
Aneh. Saya bahkan bukan ahli Scala dan dapat mengetahuinya.
HANYA PENDAPAT SAYA yang benar