Các mẫu mã Scala và Java trong đó mã Scala trông đơn giản hơn / có ít dòng hơn?


94

Tôi cần một số mẫu mã (và tôi cũng thực sự tò mò về chúng) của mã Scala và Java cho thấy mã Scala đơn giản và ngắn gọn hơn sau đó mã được viết bằng Java (tất nhiên cả hai mẫu phải giải quyết cùng một vấn đề).

Nếu chỉ có mẫu Scala với nhận xét như "đây là nhà máy trừu tượng trong Scala, trong Java sẽ trông cồng kềnh hơn nhiều" thì điều này cũng có thể chấp nhận được.

Cảm ơn!

Tôi thích nhất là được chấp nhận và câu trả lời này


3
Với một chút chân làm việc, bạn có thể tìm thấy nhiều mẫu tại rosettacode.org
nicerobot

4
Làm thế nào có thể có một câu trả lời đúng trong loại câu hỏi này?
polygenelubricants

@polygenelubricants: và bạn đề xuất gì?
Roman

10
@Roman: Chúng tôi mong đợi Scala ngắn gọn hơn. Sẽ thú vị hơn nếu bạn có thể tìm thấy thứ gì đó được diễn đạt ngắn gọn trong Java hơn là trong Scala.
Randall Schulz

1
@Randall Schulz: mọi người đều biết rằng Scala ngắn gọn hơn, nhưng đôi khi, trong mục đích học thuật, chúng ta cần một bằng chứng với các ví dụ và lý thuyết nền tảng.
Roman

Câu trả lời:


76

Hãy cải thiện ví dụ của trình xếp chồng và sử dụng các lớp trường hợp của Scala :

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

Lớp Scala ở trên chứa tất cả các tính năng của lớp Java bên dưới và một số tính năng khác - ví dụ như nó hỗ trợ khớp mẫu (mà Java không có). Scala 2.8 bổ sung các đối số được đặt tên và mặc định, được sử dụng để tạo ra một phương thức sao chép cho các lớp trường hợp, cung cấp khả năng tương tự như các phương thức with * của lớp Java sau.

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

Sau đó, khi sử dụng, chúng tôi có (tất nhiên):

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

Chống lại

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

2
Trong 2.7.x và 2.8.0 boxing duy nhất là trong productElementsunapply, không phải trong các nhà xây dựng, lĩnh vực, hoặc accessor: gist.github.com/424375
retronym

2
Khuyến khích tất cả các loại tệ nạn getter / setter. Bộ định vị chỉ nên được thêm vào khi cực kỳ miễn cưỡng, bộ định vị chỉ nên được thêm nếu cần thiết. Ví dụ điển hình về cách thêm "Sự đơn giản" dẫn đến những thói quen xấu.
Bill K

7
@Bill K: OK, sau đó chúng ta sẽ có case class Person(val firstName: String, val lastName: String) Vậy thì sao? Làm rằng điều riêng tư sẽ có thể quá, nhưng không thực hiện bất kỳ nghĩa nào đó, vì unapply, vv
soc

1
@shiva case class Person(private val firstName: String), nhưng bạn không nên sử dụng các lớp trường hợp. Thay vào đó, hãy làm class Person(firstName: String)firstNamelà riêng tư theo mặc định.
nilskp 19/09/13

1
@shiva Không. Sự khác biệt giữa valprivate vallà phương thức truy cập, tức là firstName()firstName(String), là công khai hay riêng tư. Trong Scala các trường luôn ở chế độ riêng tư. Đối với Scala để tạo các phương thức get / set kiểu Java (ngoài các trình truy cập kiểu Scala), có @BeanPropertychú thích.
Esko Luontola

45

Tôi thấy cái này ấn tượng

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)

Cũng như những cái này (xin lỗi vì không dán, tôi không muốn ăn cắp mã)


Mã scala này sẽ không tạo ra getFirstNamegetLastNamecác phương thức. Bạn phải chú thích các tham số bằng scala.reflect.BeanPropertychú thích để làm điều đó.
Abhinav Sarkar

7
@ abhin4v: Có, nhưng quy ước mã trong Scala là không có trình truy cập bắt đầu bằng get. Mã Idiomatic Java khác với mã Scala có thành ngữ. Đôi khi istiền tố được sử dụng cho boolean. davetron5000.github.com/scala-style/naming_conventions/methods/...
Esko Luontola

6
Bạn có thể thực hiện điều đó a case classvà nhận được toString, equalshashCodemiễn phí (và bạn cũng không cần phải đưa ra các đối số valmột cách rõ ràng):case class Person(firstName: String, lastName: String)
Jesper

@shiva, cho case class, không chỉ cho class.
nilskp 19/09/13

23

Nhiệm vụ: Viết chương trình đánh chỉ mục danh sách các từ khóa (như sách).

Giải trình:

  • Đầu vào: Danh sách <Chuỗi>
  • Đầu ra: Bản đồ <Ký tự, Danh sách <Chuỗi>>
  • Chìa khóa của bản đồ là 'A' đến 'Z'
  • Mỗi danh sách trong bản đồ được sắp xếp.

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

Bạn có thể sử dụng v.sorted thay vì (v sortBy danh tính).
Eastsun

1
Và với Scala 2.8, bạn có thể sử dụng mapValues (_.sorted) thay vì bản đồ {case ...}
Alex Boisvert

10
Với Java 8, mã gần như giống với Scalas: keywords.stream (). Sorted (). Collect (Collectors.groupingBy (it -> it.charAt (0))); không lừa!
Điều phối viên

11

Bài tập:

Bạn có một danh sách peoplecác đối tượng của lớp Personcó các trường nameage. Nhiệm vụ của bạn là sắp xếp danh sách này trước tiên namevà sau đó là theo 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))

Cập nhật

Kể từ khi tôi viết câu trả lời này, đã có một số tiến bộ. Các lambdas (và các tham chiếu phương thức) cuối cùng đã cập bến Java, và chúng đang tấn công thế giới Java như một cơn bão.

Đây là đoạn mã trên sẽ trông như thế nào với Java 8 (do @fredoverflow đóng góp):

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

Mặc dù mã này gần như ngắn, nhưng nó không hoạt động hoàn toàn thanh lịch như mã Scala.

Trong giải pháp Scala, các Seq[A]#sortByphương pháp chấp nhận một chức năng A => BBlà cần thiết để một Ordering. Orderinglà một loại-lớp. Hãy suy nghĩ tốt nhất về cả hai thế giới: Giống như Comparable, nó ngầm đối với loại được đề cập, nhưng giống như Comparator, nó có thể mở rộng và có thể được thêm vào hồi tố cho các loại không có nó. Vì Java thiếu các lớp kiểu nên nó phải sao chép mọi phương thức như vậy, một lần cho Comparable, sau đó cho Comparator. Ví dụ, xem comparingthenComparing ở đây .

Các lớp kiểu cho phép người ta viết các quy tắc như "Nếu A có thứ tự và B có thứ tự, thì bộ của chúng (A, B) cũng có thứ tự". Trong mã, đó là:

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

Đó là cách mà sortBymã trong mã của chúng ta có thể so sánh theo tên và sau đó theo tuổi. Các ngữ nghĩa đó sẽ được mã hóa bằng "quy tắc" trên. Một lập trình viên Scala sẽ trực giác mong đợi điều này hoạt động theo cách này. Không có phương pháp mục đích đặc biệt nào comparingphải được thêm vào Ordering.

Lambdas và các tham chiếu phương thức chỉ là phần nổi của tảng băng trôi đó là lập trình chức năng. :)


Thiếu lambdas (hoặc ít nhất là tham chiếu phương thức) là tính năng quan trọng nhất mà tôi bỏ lỡ trong Java.
Petr Gladkikh

@fredoverflow Cảm ơn bạn đã thêm ví dụ về Java 8. Nó vẫn chứng tỏ tại sao cách tiếp cận của Scala lại ưu việt hơn. Tôi sẽ bổ sung thêm sau.
missfaktor

@rakemous, anh bạn, câu trả lời đã được viết hơn sáu năm trước.
missfaktor

10

Bài tập:

Bạn có một tệp XML "company.xml" trông giống như sau:

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

Bạn phải đọc tệp này và in các trường firstNamelastNametrường của tất cả các nhân viên.


Java: [lấy từ đây ]

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: [lấy từ đây , 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 bởi Bill; Kiểm tra bình luận cho cuộc thảo luận] -

Hmm, làm thế nào để làm điều đó mà không trả lời trong phần trả lời chưa được định dạng ... Hmph. Tôi đoán tôi sẽ chỉnh sửa câu trả lời của bạn và cho phép bạn xóa nó nếu nó gây lỗi cho bạn.

Đây là cách tôi sẽ làm điều đó trong Java với các thư viện tốt hơn:

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

Đây chỉ là một vụ hack nhanh chóng không liên quan đến phép thuật và tất cả các thành phần có thể tái sử dụng. Nếu tôi muốn thêm một số phép thuật, tôi có thể làm điều gì đó tốt hơn là trả về một mảng chuỗi chuỗi, nhưng ngay cả khi GoodXMLLib này cũng sẽ hoàn toàn có thể tái sử dụng được. Tham số đầu tiên của scanFor là phần, tất cả các tham số trong tương lai sẽ là các mục cần tìm bị hạn chế, nhưng giao diện có thể được nâng cấp một chút để thêm nhiều cấp độ phù hợp mà không có vấn đề thực sự.

Tôi sẽ thừa nhận rằng Java có một số hỗ trợ thư viện khá kém nói chung, nhưng thôi - để so sánh việc sử dụng thư viện XML cũ hàng chục năm (?) Của Java với một triển khai được thực hiện dựa trên sự ngắn gọn là không công bằng - và còn xa so sánh giữa các ngôn ngữ!


hmm, ví dụ Java sẽ ngắn hơn và đẹp hơn với trình phân tích cú pháp SAX hoặc StAX. Nhưng SCALA vẫn là một trong những thực sự tốt
oluies Ngày

5
Mã Java được viết chính xác để phân tích cú pháp tệp XML cụ thể đó mà không cần sử dụng lại và có rất nhiều mã trùng lặp. Ai đã viết nó hoặc cố tình cố tình trông như thể anh ta không hiểu mã hóa hoặc không hiểu mã hóa.
Bill K

@Bill K: Tôi chưa bao giờ thực hiện phân tích cú pháp XML trong Java nên tôi đã chọn ví dụ này từ một số trang web ngẫu nhiên. Hãy thoải mái chỉnh sửa phần Java của câu trả lời, tôi không phiền.
missfaktor

Vâng, hãy giả sử rằng bạn đang nói về sự khác biệt ngôn ngữ chứ không phải sự khác biệt về thư viện - trong trường hợp đó, cả hai sẽ gần giống nhau. Sự khác biệt duy nhất về ngôn ngữ trong ví dụ thứ hai là đối sánh / trường hợp có thể được thực hiện trong một dòng duy nhất dưới dạng vòng lặp for nếu được thư viện triển khai theo cách đó.
Bill K

@Bill K: Không, bạn đã sai hoàn toàn. Có hai tính năng Scala rất mạnh ở đây: 1. Văn bản XML 2. Khớp mẫu. Java không có một trong hai thứ này. Vì vậy, mã Java tương đương được viết trong một số thư viện giả định chắc chắn sẽ KHÔNG giống hệt nhau. (Hãy thử văn bản, bạn sẽ biết.)
missingfaktor

10

Bản đồ các hành động cần thực hiện tùy thuộc vào một chuỗi.

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

Và tất cả được thực hiện theo hương vị tốt nhất có thể!

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, tôi nghĩ rằng chỉnh sửa của bạn không chính xác. todos.get("hi")lợi nhuận Option[()=>Unit]cần thiết để khớp đúng.
huynhjl

@huynhjl, My xấu quá. Cuộn nó lại.
missfaktor

3
Có thể còn ngắn hơn:val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
Geoff Reedy

2
Thậm chí ngắn hơn: val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }và sau đótodos("hi")()
Martin Ring

8

Bây giờ tôi đang viết một trò chơi Blackjack trong Scala. Đây là cách phương thức agentWins của tôi trông như thế nào trong Java:

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

Đây là cách nó trông như thế nào trong Scala:

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

Hoan hô các chức năng bậc cao!

Giải pháp Java 8:

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

scala có cú pháp rất khó. cần phải nhớ rất nhiều :-(
AZ_

Scala giống như CSS, có nhiều thuộc tính và thuộc tính cần nhớ
AZ_

1
tốt hơn:def dealerWins = !(players exists (_ beats dealer))
Kevin Wright

7

Tôi thích ví dụ đơn giản về sắp xếp và chuyển đổi này, được trích từ cuốn sách 'Khởi đầu Scala' của David Pollak:

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

Trong Java:

public static List<String> validByAge(List<Person> in) {
   List<Person> people = new ArrayList<Person>();
   for (Person p: in) {
     if (p.valid()) people.add(p);
   }
   Collections.sort(people, new Comparator<Person>() {
      public int compare(Person a, Person b) {
        return a.age() - b.age();
      } 
   } );
   List<String> ret = new ArrayList<String>();
     for (Person p: people) {
       ret.add(p.first);
     }
   return ret;
}

public class Person {
    private final String firstName;
    private final String lastName;
    private final Integer age;
    public Person(String firstName, String lastName, Integer age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    public String getFirst() {
        return firstName;
    }
    public String getLast() {
        return lastName;
    }
    public Integer getAge() {
       return age;
    }
    public Boolean valid() {
       return age > 18;
    }
}

List<Person> input = new ArrayList<Person>();
input.add(new Person("John", "Valid", 32));
input.add(new Person("John", "InValid", 17));
input.add(new Person("OtherJohn", "Valid", 19));

List<Person> output = validByAge(input)

6

Còn Quicksort thì sao?


Java

Sau đây là một ví dụ về java được tìm thấy qua tìm kiếm trên google,

URL là 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

Một nỗ lực nhanh chóng với một phiên bản Scala. Mở mùa giải cho những người cải tiến mã; @)

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
Sự nhanh chóng đó trên danh sách được liên kết có độ phức tạp về thời gian O (n ^ 2) hay không? Thông thường hợp nhất hoặc tương tự được sử dụng cho danh sách liên kết.
Esko Luontola

3
Nó cũng đệ quy không đuôi và do đó không thích hợp như một thuật toán performant (hoặc một trong đó sẽ không tràn stack)
oxbow_lakes

Cảm ơn vì những ý kiến ​​hữu ích. Tôi đã thấy quicksort được viết như thế này ở đâu đó và bị ấn tượng bởi sự nhỏ gọn của nó, rõ ràng là tôi đã không cân nhắc nhiều. Tôi bị cuốn theo phép so sánh LOC, vốn luôn là một thứ hấp dẫn với Scala v Java.
Don Mackenzie

2
Quicksort không phải là O (n ^ 2) trong danh sách chức năng, nhưng nó chắc chắn có mối nguy hiểm đó. Về mặt tiệm cận, nó vẫn là trung bình O (n log n) , nhưng có xác suất thống kê cao hơn khi gặp trường hợp xấu nhất là O (n ^ 2) vì chúng tôi luôn chọn điểm xoay ở đầu danh sách, thay vì chọn một cách ngẫu nhiên .
Daniel Spiewak

Lọc hai lần là không tốt. Xem trong câu trả lời của tôi cho câu hỏi của bạn, việc sử dụng partitionđể tránh điều đó.
Daniel C. Sobral

6

Tôi thích câu trả lời của người dùng chưa biết nên tôi sẽ cố gắng cải thiện nó. Đoạn mã dưới đây không phải là bản dịch trực tiếp của ví dụ Java, nhưng nó hoàn thành cùng một nhiệm vụ với cùng một 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)
}

Hiện tại, tôi chưa cài đặt scala-2.8, để kiểm tra đoạn mã này, nhưng tôi đoán tôi có thể thấy ý định là gì - chỉ 'từ khóa' hoàn toàn không được sử dụng. Nó tạo ra một bản đồ của tất cả các Chuỗi và tần số của chúng, phải không?
người dùng không xác định

@user Có, đó là những gì nó làm. Đó không phải là những gì được hoàn thành bởi mã của bạn? Ồ, tôi hiểu rồi. Tôi đã sao chép sai dòng. Tôi sẽ sửa nó ngay bây giờ. :-)
Daniel C. Sobral

6

Tôi thích phương pháp getOrElseUpdate, được tìm thấy trong mutableMap và được hiển thị ở đây, Java đầu tiên, không có:

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

có - một WordCount, và ở đây trong 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
}

Và đây là trong 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;
}

Và nếu bạn muốn hoạt động 100%:

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

filtersortđã được hiển thị, nhưng hãy xem chúng được tích hợp với bản đồ dễ dàng như thế nào:

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

Tôi thích ví dụ này rất nhiều. Nó tránh được con đường dễ dàng so sánh các lớp trường hợp và không mắc lỗi hiển thị mã Scala chứ không phải mã Java tương đương.
Daniel C. Sobral

5

Đây là một ví dụ rất đơn giản: Số nguyên bình phương và sau đó thêm chúng


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

Trong scala:


val ar = Array(1,2,3)
def square(x:Int) = x * x
def add(s:Int,i:Int) = s+i

ar.map(square).foldLeft(0)(add)

Bản đồ thu gọn áp dụng chức năng cho tất cả các phần tử của mảng, vì vậy:

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

Gấp trái là sẽ bắt đầu bằng 0 làm (các) bộ tích lũy và áp dụng add(s,i)cho tất cả các phần tử (i) của mảng, sao cho:

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

Bây giờ điều này có thể được nén lại thành:

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

Cái này tôi sẽ không thử trong Java (còn nhiều việc nữa), hãy chuyển XML thành Bản đồ:


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

Một lớp lót khác để lấy bản đồ từ 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)

Vấn đề với bạn sumSquaretrong Scala là nó trông rất khó hiểu để một nhà phát triển Java, mà sẽ cung cấp cho họ đạn chống lại bạn phàn nàn rằng Scala là mơ hồ và phức tạp ...
Jesper

Tôi đã định dạng lại một chút để cải thiện ví dụ. Hy vọng rằng điều này không làm tổn thương Scala.
Thomas

5
scala> 1 đến 10 map (x => x * x) sum res0: Int = 385 Hãy xem nhà phát triển java gọi điều đó thật khó hiểu. Tại thời điểm đó, những ngón tay trong tai nói nah-nah-nah.
psp

3
@Jesper Đối với một nhà phát triển không phải Java, Java trông giống như một lượng lớn bảng soạn sẵn và nhiễu dòng. Điều đó không có nghĩa là bạn không thể hoàn thành công việc thực sự bằng ngôn ngữ.
James Moore

Bạn có thể sử dụng ReduceLeft (thêm) thay vì foldLeft (0) (thêm). Tôi nghĩ sẽ dễ đọc hơn khi phần tử bắt đầu của bạn là phần tử không / danh tính của nhóm.
Debilski

5

Vấn đề: bạn cần thiết kế một phương thức sẽ thực thi bất kỳ mã đã cho nào một cách không đồng bộ.

Giải pháp trong 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
            }
});

Điều tương tự trong Scala (sử dụng các diễn viên):

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
Kể từ ngày 2.8, điều này có thể được viết là Futures.future {body} và thực sự mạnh mẽ hơn vì tương lai được trả về bởi điều này có thể được kết hợp để nhận giá trị mà nó cuối cùng đánh giá.
Dave Griffith

3

Mô hình Circuit Breaker từ Michael Nygard's Release It in FaKods ( liên kết tới mã )

triển khai trông giống như thế này trong Scala:

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


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

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

Mà tôi nghĩ là siêu đẹp. Nó trông giống như một khối ngôn ngữ nhưng nó là một mixin đơn giản trong Đối tượng CircuitBreaker thực hiện mọi công việc.

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

Tham khảo bằng các ngôn ngữ khác Google cho "Bộ ngắt mạch" + ngôn ngữ của bạn.


3

Tôi đang chuẩn bị một tài liệu đưa ra một số ví dụ về mã Java và Scala, chỉ sử dụng các tính năng đơn giản dễ hiểu của Scala:

Scala: Java tốt hơn

Nếu bạn muốn tôi thêm điều gì đó vào nó, vui lòng trả lời trong phần bình luận.


Tiêu đề "Scala: Một tốt hơn Java" được missleading
duckhunt

2

Tại sao không ai đăng bài này trước đây:

Java:

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

116 ký tự.

Scala:

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

56 ký tự.


1
Applicationtính trạng coi là có hại ... scala-blogs.org/2008/07/...
missingfaktor

1

Các luồng vô hạn được đánh giá một cách lười biếng là một ví dụ điển hình:

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

}

Đây là một câu hỏi giải quyết các luồng vô hạn trong Java: Một thiết kế vòng lặp vô hạn có tồi không?

Một ví dụ điển hình khác là các hàm và bao đóng của lớp đầu tiên:

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 không hỗ trợ các hàm lớp đầu tiên và việc bắt chước các bao đóng với các lớp ẩn danh bên trong không phải là rất thanh lịch. Một điều khác mà ví dụ này cho thấy rằng java không thể làm là chạy mã từ trình thông dịch / REPL. Tôi thấy điều này vô cùng hữu ích để kiểm tra nhanh các đoạn mã.


Xin lưu ý rằng sàng quá chậm để thực tế.
Elazar Leibovich

@oxbow_lakes không có java tương đương cho các ví dụ này.
dbyrne

@dbyme Không đúng. Bạn có thể dễ dàng phân lớp của Java IterableIteratortạo ra các luồng vô hạn.
Daniel C. Sobral

@dbyrne "Một điều khác mà ví dụ này cho thấy rằng java không thể làm là chạy mã từ trình thông dịch / REPL. Tôi thấy điều này vô cùng hữu ích để kiểm tra nhanh các đoạn mã." Tôi sử dụng trang sổ lưu niệm trong Eclipse để thử các đoạn mã Java. Làm hầu hết nếu không phải tất cả Java đều hoạt động trong IDE đó, tôi không cần REPL. Tôi đã sử dụng notepad.exe và javac trong những ngày đầu tiên của mình khi tôi không chắc chắn về ngôn ngữ hoặc tính năng thư viện và sau một thời gian ngắn, nó hoạt động rất tốt và nhanh - mặc dù REPL có phần dễ sử dụng hơn - và nhanh hơn. Tôi có thể đã tránh hoàn toàn vụ hack notepad bằng cách cài đặt VisualAge mà chúng tôi đã có

0

Mã Scala này ...

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

... sẽ hoàn toàn không thể đọc được trong Java, nếu có thể.


10
OPINIO đúng của tôi: cảm ơn vì câu trả lời! nhưng bạn có thể vui lòng giải thích những gì xảy ra ở đó? Tôi chưa quen với cú pháp Scala và (đó là lý do có thể xảy ra) nó trông hoàn toàn không thể đọc được ngay cả đối với tôi bây giờ.
Roman

Đó là phân vùng một danh sách chung kiểu T bằng cách sử dụng một hàm phân vùng được cung cấp làm chức năng bảo vệ trong các mệnh đề khớp mẫu của câu lệnh case.
CHỈ LÀ Ý KIẾN chính xác của TÔI,

3
Kỳ dị. Tôi thậm chí không phải là một chuyên gia Scala từ xa và có thể tìm ra điều đó.
CHỈ LÀ Ý KIẾN chính xác của tôi,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.