Scala kodunun daha basit göründüğü / daha az satıra sahip olduğu Scala ve Java kodu örnekleri?


95

Scala ve Java kodunun bazı kod örneklerine ihtiyacım var (ve bunları gerçekten merak ediyorum), Scala kodunun Java ile yazılmış koddan daha basit ve öz olduğunu gösteriyor (tabii ki her iki örnek de aynı sorunu çözmeli).

"Bu Scala'da soyut fabrika, Java'da çok daha hantal görünecek" gibi yorumlarla sadece Scala örneği varsa, bu da kabul edilebilir.

Teşekkürler!

En çok kabul edilenleri seviyorum ve bu cevaplar


3
Biraz bacak çalışmasıyla rosettacode.org'da
nicerobot

4
Bu tür bir soruda nasıl tek bir doğru cevap olabilir?
poligenel yağlayıcılar

@polygenelubricants: ve ne öneriyorsunuz?
Roman

10
@Roman: Scala'nın daha özlü olmasını bekliyoruz. Java'da Scala'da olduğundan daha net bir şekilde ifade edilen bir şey bulabilirseniz daha ilginç olurdu.
Randall Schulz

1
@Randall Schulz: Scala'nın daha özlü olduğunu herkes bilir, ancak bazen akademik amaçla örnekler ve arka plan teorisi ile bir kanıta ihtiyacımız var.
Roman

Yanıtlar:


77

İstifleyici örneğini geliştirelim ve Scala'nın durum sınıflarını kullanalım :

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

Yukarıdaki Scala sınıfı, aşağıdaki Java sınıfının tüm özelliklerini ve daha fazlasını içerir - örneğin, kalıp eşleştirmeyi destekler (Java'da yoktur). Scala 2.8 , aşağıdaki Java sınıfının with * yöntemleriyle aynı yeteneği sağlayan, vaka sınıfları için bir kopyalama yöntemi oluşturmak için kullanılan adlandırılmış ve varsayılan argümanlar ekler .

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

Sonra, kullanımda (elbette):

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

Karşısında

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

2
2.7.x ve 2.8.0 sadece boks içindedir productElementsve unapply: değil yapıcı, alan veya erişimci içinde, gist.github.com/424375
retronym

2
Her türlü alıcı / pasör kötülüğünü teşvik eder. Ayarlayıcılar yalnızca aşırı isteksizlikle eklenmelidir, alıcılar yalnızca gerektiğinde eklenmelidir. "Basitlik" eklemenin kötü alışkanlıklara nasıl yol açtığına dair güzel bir örnek.
Bill K

7
@ Bill K: Tamam, o zaman bizde olacağız case class Person(val firstName: String, val lastName: String) Peki ne olacak ? Bu şeyi özel yapmak da mümkün olabilir, ancak uygulanmaması vb. Nedeniyle hiçbir anlam ifade etmiyor
soc

1
@shiva case class Person(private val firstName: String), ancak o zaman vaka sınıflarını kullanmamalısın. Bunun yerine yapın class Person(firstName: String)ve firstNamevarsayılan olarak özeldir.
nilskp

1
@shiva sayılı arasındaki fark valve private valerişimci yöntemleri olup, örneğin yani firstName()ve firstName(String)kamu veya özel. Scala'da alanlar her zaman özeldir. Scala'nın Java tarzı get / set yöntemleri oluşturması için (Scala tarzı erişimcilere ek olarak), @BeanPropertyaçıklama vardır.
Esko Luontola

45

Bunu etkileyici buldum

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)

Bunların yanı sıra (yapıştırmadığım için üzgünüm, kodu çalmak istemedim)


Bu scala kodu oluşturmayacak getFirstNameve getLastNameyöntemler. Bunu yapmak için parametrelere scala.reflect.BeanPropertyaçıklama eklemeniz gerekir.
Abhinav Sarkar

7
@ abhin4v: Evet, ancak Scala'daki kod kuralı, ön ekli erişimcilerin olmamasıdır get. Deyimsel Java kodu deyimsel Scala kodundan farklıdır. Bazen isboole'lar için kullanılan önek. davetron5000.github.com/scala-style/naming_conventions/methods/…
Esko Luontola

7
Bir o yapabilir case classve almak toString, equalsve hashCodeücretsiz olarak (ve ayrıca argümanları yapmak gerekmez val: Açıkça)case class Person(firstName: String, lastName: String)
Jesper

@shiva için case class, sadece için değil class.
nilskp

23

Görev: Bir anahtar kelime listesini (kitaplar gibi) indekslemek için bir program yazın.

Açıklama:

  • Giriş: List <String>
  • Çıktı: Map <Character, List <String>>
  • Haritanın anahtarı "A" dan "Z" ye kadardır
  • Haritadaki her liste sıralanır.

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

(V sortBy kimlik) yerine v.sorted kullanabilirsiniz.
Eastsun

1
Scala 2.8 ile, map {case ...} yerine mapValues ​​(_.sorted) kullanabilirsiniz
Alex Boisvert

10
Java 8 ile, kod Scalas ile neredeyse aynıdır: keywords.stream (). Sıralı (). Collect (Collectors.groupingBy (it -> it.charAt (0))); hile yapar!
Koordinatör

11

Görev:

Ve alanları peopleolan sınıf nesnelerinin bir listesine sahipsiniz . Sizin göreviniz bu listeyi önce göre sonra da sıralamaktır .Personnameagenameage

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

Güncelleme

Bu cevabı yazdığımdan beri epey ilerleme oldu. Lambdalar (ve yöntem referansları) sonunda Java'ya indi ve Java dünyasını fırtınaya sürüklüyorlar.

Java 8 ile yukarıdaki kod şöyle görünecektir (@fredoverflow tarafından katkıda bulunmuştur):

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

Bu kod neredeyse kısa olmasına rağmen Scala kodu kadar zarif çalışmıyor.

Scala çözümde, Seq[A]#sortByyöntem, bir işlevi kabul etmek gereklidir sahip bir . bir tür sınıfıdır. Her iki dünyayı da en iyi şekilde düşünün: Söz konusu tür için örtüktür, ancak genişletilebilir ve ona sahip olmayan türlere geriye dönük olarak eklenebilir. Java, tür sınıfları içermediğinden, bu tür her yöntemi bir kez , sonra da için çoğaltması gerekir . Örneğin, bakın ve buraya .A => BBOrderingOrderingComparableComparatorComparableComparatorcomparingthenComparing

Tür sınıfları, "A'nın sıralaması ve B'nin sıralaması varsa, o zaman tuple (A, B) de sıralaması vardır" gibi kurallar yazmasına izin verir. Kodda, yani:

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

Bu, kodumuzda sortByisme göre ve sonra yaşa göre karşılaştırabilir. Bu anlambilim yukarıdaki "kural" ile kodlanacaktır. Bir Scala programcısı sezgisel olarak bunun bu şekilde çalışmasını beklerdi. Buna benzer özel amaçlı yöntemler comparingeklenmemiştir Ordering.

Lambdalar ve yöntem referansları, işlevsel programlama olan bir buzdağının sadece bir ucu. :)


Eksik lambdalar (veya en azından yöntem referansları) Java'da özlediğim en önemli özelliktir.
Petr Gladkikh

@fredoverflow Java 8 örneğini eklediğiniz için teşekkürler. Hala Scala'nın yaklaşımının neden üstün olduğunu gösteriyor. Daha sonra ekleyeceğim.
missingfaktor

@rakemous, dostum, cevap altı yıldan fazla bir süre önce yazıldı.
missingfaktor

10

Görev:

Aşağıdaki gibi görünen bir "company.xml" XML dosyanız var:

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

Bu dosyayı okumanız firstNameve lastNametüm çalışanların ve alanlarını yazdırmanız gerekir .


Java: [ buradan alınmıştır ]

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: [ buradan alınmıştır , slayt # 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)
        } 
      }
    }
  }
}

[Bill tarafından DÜZENLE; Tartışma için yorumları kontrol edin] -

Hmm, biçimlendirilmemiş bir yanıt bölümünde yanıtlamadan nasıl yapılır ... Hmph. Sanırım cevabınızı düzenleyeceğim ve sizi rahatsız ederse silmenize izin vereceğim.

Daha iyi kitaplıklarla Java'da bunu şu şekilde yapardım:

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

Bu, sihir içermeyen ve tüm yeniden kullanılabilir bileşenleri içeren hızlı bir saldırıdır. Biraz sihir eklemek isteseydim, bir dizi dizi dizisi döndürmekten daha iyi bir şey yapabilirdim, ancak bu GoodXMLLib bile tamamen yeniden kullanılabilir olacaktır. ScanFor'un ilk parametresi bölümdür, gelecekteki tüm parametreler sınırlı olanı bulunacak öğeler olacaktır, ancak arabirim, gerçek bir sorun olmadan birden çok eşleştirme düzeyi eklemek için hafifçe parlatılabilir.

Java'nın genel olarak oldukça zayıf bir kütüphane desteğine sahip olduğunu itiraf edeceğim, ama hadi - Java'nın on yıllık (?) Eski XML kütüphanesinin korkunç kullanımını, kısa süreli olmaya dayalı bir uygulama ile karşılaştırmak adil değil - ve çok uzak dillerin karşılaştırmasından!


hmm, Java örneği daha kısa ve SAX veya StAX ayrıştırıcıyla daha iyi görünecektir. Ama yine de SCALA gerçekten güzel
oluies

5
Java kodu, belirli bir XML dosyasını, yeniden kullanım ve çok sayıda yinelenen kod olmadan tam olarak ayrıştırmak için yazılmıştır. Kim yazdıysa, kasıtlı olarak kodlamayı anlamıyor veya kodlamayı anlamıyor gibi görünmeye çalışıyordu.
Bill K

@Bill K: Java'da hiç XML ayrıştırma yapmadım, bu yüzden bu örneği rastgele bir siteden seçtim. Cevabın Java kısmını düzenlemekten çekinmeyin, sorun değil.
missingfaktor

Pekala, kitaplık farklılıklarından değil, dil farklılıklarından bahsettiğinizi varsayalım - bu durumda ikisi neredeyse aynı olacaktır. İkinci örnekteki tek dil farkı, kütüphane tarafından bu şekilde uygulanırsa, for döngüsü olarak tek bir satırda yapılabilecek eşleştirme / durum şeyidir.
Bill K

@Bill K: Hayır, tamamen yanılıyorsun. Burada çalışan iki çok güçlü Scala özelliği vardır: 1. XML Değişmezleri 2. Örüntü Eşleştirme. Java bunlardan hiçbirine sahip değil. Bu nedenle, bazı varsayımsal kitaplıklarda yazılan eşdeğer Java kodu kesinlikle aynı OLMAYACAKTIR. (
Yazmayı

10

Bir dizeye bağlı olarak gerçekleştirilecek eylemlerin haritası.

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

Ve hepsi mümkün olan en iyi tatta yapılır!

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, düzenlemenizin yanlış olduğunu düşünüyorum. düzgün eşleşmesi için gerekli olan todos.get("hi")döndürür Option[()=>Unit].
huynhjl

@huynhjl, Benim hatam. Geri yuvarladım.
missingfaktor

3
Daha da kısa olabilir:val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
Geoff Reedy

2
Daha da kısa: val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }ve sonratodos("hi")()
Martin Ring

8

David Pollak'ın 'Beginning Scala' kitabından alınan bu basit sıralama ve dönüştürme örneğini beğendim:

Scala'da:

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

Java'da:

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)

8

Şimdi Scala'da bir Blackjack oyunu yazıyorum. DealerWins yöntemim Java'da şu şekilde görünür:

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

Scala'da şöyle görünüyor:

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

Yaşasın, üst düzey işlevler!

Java 8 çözümü:

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

scala çok zor sözdizimine sahiptir. çok fazla şey hatırlamanız gerekiyor :-(
AZ_

Scala, hatırlanması gereken birçok özellik ve özellik açısından CSS gibidir
AZ_

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

6

Quicksort'a ne dersiniz?


Java

Aşağıda, bir google araması yoluyla bulunan bir java örneği verilmiştir,

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

Scala versiyonunda hızlı bir deneme. Kod geliştiriciler için açık sezon; @)

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
Bağlantılı listelerdeki bu hızlı sıralama O (n ^ 2) zaman karmaşıklığına sahip mi yoksa yok mu? Bağlantılı listeler için genellikle birleştirme veya benzeri kullanılır.
Esko Luontola

3
Kuyruk özyinelemeli de değildir ve bu nedenle performans algoritması olarak uygun değildir (veya yığını
aşmayacak

Faydalı yorumlar için teşekkürler. Quicksort'un bir yerlerde böyle yazıldığını görmüştüm ve kompaktlığından etkilendim, açıkça pek dikkate almadım. Scala v Java ile her zaman baştan çıkarıcı bir şey olan LOC karşılaştırmasına kapıldım.
Don Mackenzie

2
Quicksort, işlevsel listelerde O (n ^ 2) değildir , ancak kesinlikle bu tehlikeye sahiptir. Asimptotik olarak, hala ortalama O (n log n) , ancak en kötü durum olan O (n ^ 2) isabet etme olasılığının daha yüksek bir istatistiksel olasılığı var çünkü rastgele birini seçmek yerine her zaman listenin başındaki pivot noktasını seçiyoruz .
Daniel Spiewak

İki kez filtrelemek kötüdür. Sorunuza verdiğim cevabın partitionbundan kaçınmak için kullanımına bakın .
Daniel C. Sobral

6

Ben sevdim kullanıcı bilinmeyen en cevabı o kadar çok şey bunun üzerine geliştirmeye çalışmak için gidiyorum. Aşağıdaki kod , Java örneğinin doğrudan çevirisi değildir , ancak aynı görevi aynı API ile gerçekleştirir.

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

Şimdiye kadar bu pasajı test etmek için scala-2.8 yüklü değil, ama sanırım neyin amaçlandığını görebiliyorum - sadece 'anahtar kelimeler' hiç kullanılmıyor. Tüm Tellerin ve frekanslarının bir haritasını çıkarır, değil mi?
kullanıcı bilinmiyor

@user Evet, yaptığı şey bu. Kodunuzla başaran bu değil mi? Ah anlıyorum. Yanlış satırı kopyaladım. Hemen şimdi düzelteceğim. :-)
Daniel C. Sobral

6

MutableMap'te bulunan ve burada gösterilen getOrElseUpdate yöntemini çok seviyorum, ilk olarak Java, şu olmadan

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

evet - bir WordCount ve burada ölçek olarak:

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
}

Ve işte Java 8'de:

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

Ve% 100 işlevselliğe geçmek istiyorsanız:

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

filterve sortzaten gösterildi, ancak haritayla ne kadar kolay entegre olduklarına bakın:

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

Bu örneği çok beğendim. Vaka sınıflarını karşılaştırmanın kolay yolunu önler ve Java eşdeğerini değil Scala kodunu gösterme hatasını yapmaz.
Daniel C. Sobral

5

Bu çok basit bir örnek: Tam sayıları kare ve sonra onları ekle


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

Ölçek olarak:


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)

Kompakt eşleme, işlevi dizinin tüm öğelerine uygular, bu nedenle:

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

Sola katlama, toplayıcı (lar) olarak 0 ile başlar add(s,i)ve dizinin tüm öğelerine (i) uygulanır , böylece:

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

Şimdi bu, şu şekilde daha da sıkıştırılabilir:

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

Bunu Java'da denemeyeceğim (çok çalışmak için), XML'i bir Haritaya çevirin:


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

Haritayı XML'den almak için başka bir satır:


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)

Scala'yla ilgili sorun, sumSquarebir Java geliştiricisine çok şifreli görünmesi ve Scala'nın belirsiz ve karmaşık olduğundan şikayet etmeleri için onlara cephane vermesi ...
Jesper

Örneği iyileştirmek için biraz yeniden biçimlendirdim. Umarım bu Scala'ya zarar vermez.
Thomas

5
scala> 1 ila 10 map (x => x * x) toplamı res0: Int = 385 Bakalım java geliştiricisinin buna şifreli dediğini görelim. Bu noktada kulaklarında nah-nah-nah diyen parmaklar var.
psp

3
@Jesper Java olmayan bir geliştirici için Java, büyük miktarda standart metin ve satır gürültüsü gibi görünür. Bu, dilde gerçek iş yapamayacağınız anlamına gelmez.
James Moore

FoldLeft (0) (add) yerine azaltmakLeft (add) kullanabilirsiniz. Başlangıç ​​öğeniz grubun sıfır / kimlik öğesi olduğunda okumanın daha kolay olduğunu düşünüyorum.
Debilski

5

Sorun: Herhangi bir kodu eşzamansız olarak yürütecek bir yöntem tasarlamanız gerekir. Java'da

Çözüm :

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

Scala'da aynı şey (oyuncuları kullanarak):

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
2.8 itibariyle, bu Futures.future {body} olarak yazılabilir ve aslında daha güçlüdür çünkü bunun getirdiği gelecek, sonunda değerlendirdiği değeri elde etmek için birleştirilebilir.
Dave Griffith

3

Dan Kesici desen Michael Nygård en Release It içinde FaKods ( koduna bağlantı )

uygulama Scala'da şöyle görünür:

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


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

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

Bence çok hoş. Dilin bir parçası gibi görünür, ancak tüm işi yapan CircuitBreaker Nesnesinde basit bir karışımdır .

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

Diğer dillerde Google "Devre kesici" + sizin diliniz için referans.


3

Scala'nın yalnızca anlaşılması kolay özelliklerini kullanan birkaç Java ve Scala kodu örneği veren bir belge hazırlıyorum:

Scala: Daha iyi bir Java

Bir şey eklememi isterseniz, lütfen yorumlarda yanıtlayın.


"Scala: Daha iyi bir Java" başlığı yanlış yönlendiriliyor
duckhunt

2

Tembel değerlendirilen sonsuz akışlar buna iyi bir örnektir:

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

}

Java'da sonsuz akışları ele alan bir soru: Sonsuz yineleyici kötü bir tasarım mı?

Bir başka güzel örnek, birinci sınıf işlevler ve kapanışlardır:

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 birinci sınıf işlevleri desteklemez ve anonim iç sınıflarla kapanışları taklit etmek çok zarif değildir. Bu örneğin, java'nın yapamayacağını gösteren başka bir şey de, bir yorumlayıcıdan / REPL'den kod çalıştırmaktır. Bunu kod parçacıklarını hızlı bir şekilde test etmek için son derece yararlı buluyorum.


Lütfen eleğin pratik olamayacak kadar yavaş olduğuna dikkat edin.
Elazar Leibovich

@oxbow_lakes bu örnekler için eşdeğer java yoktur.
dbyrne

@dbyme Doğru değil. Java'ları kolayca alt sınıflara ayırabilir Iterableve Iteratorsonsuz akışlar üretebilirsiniz.
Daniel C. Sobral

@dbyrne "Bu örnekte java'nın yapamayacağı başka bir şey de bir yorumlayıcıdan / REPL'den kod çalıştırmaktır. Bunu kod parçacıklarını hızlı bir şekilde test etmek için son derece yararlı buluyorum." Java parçacıklarını denemek için Eclipse'de bir not defteri sayfası kullanıyorum. Tüm Java bu IDE'de çalışmıyorsa çoğunu yapmak, REPL'e ihtiyacım yok. İlk günlerimde, bir dil veya kitaplık özelliğinden emin olmadığım ve kısa bir süre sonra çok iyi ve hızlı gittiğimde notepad.exe ve javac kullandım - REPL'in kullanımı biraz daha kolay olsa da - ve daha hızlı. Zaten içinde bulunduğumuz

2

Neden bunu daha önce kimse yayınlamadı:

Java:

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.


1
Applicationkabul zararlı ... trait scala-blogs.org/2008/07/...
missingfaktor

0

Bu Scala kodu ...

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

... mümkünse Java'da tamamen okunamaz olacaktır.


10
DOĞRU OPINYO: cevabınız için teşekkürler! ama orada ne olduğunu açıklar mısınız lütfen? Henüz Scala sözdizimine aşina değilim ve (olası nedeni budur) benim için şimdi bile tamamen okunamaz görünüyor.
Roman

Case ifadesinin desen eşleştirme cümlelerinde bir koruma olarak sağlanan bir bölümleme işlevini kullanarak genel bir T türü listesini bölümlere ayırıyor.
SADECE

3
Tuhaf. Uzaktan bir Scala uzmanı bile değilim ve bunu çözebilirim.
SADECE
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.