【问题标题】:Samples of Scala and Java code where Scala code looks simpler/has fewer lines?Scala 代码看起来更简单/行数更少的 Scala 和 Java 代码示例?
【发布时间】:2011-02-26 12:29:01
【问题描述】:

我需要一些 Scala 和 Java 代码的代码示例(我也对它们很好奇),这表明 Scala 代码比用 Java 编写的代码更简单和简洁(当然这两个示例应该解决相同的问题)。

如果只有 Scala 示例带有“这是 Scala 中的抽象工厂,在 Java 中看起来更麻烦”之类的注释,那么这也是可以接受的。

谢谢!

我最喜欢接受和this 的答案

【问题讨论】:

  • 稍加努力,您可能会在rosettacode.org找到大量样本
  • 这样的问题怎么会有一个正确答案?
  • @polygenelubricants:你有什么建议?
  • @Roman:我们希望 Scala 更简洁。如果你能找到用 Java 比用 Scala 更简洁地表达的东西会更有趣。
  • @Randall Schulz:大家都知道 Scala 更简洁,但有时,出于学术目的,我们需要有例子和背景理论的证明。

标签: java scala comparison language-features


【解决方案1】:

让我们改进stacker's example 并使用Scala 的case classes

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

上面的 Scala 类包含下面 Java 类的所有特性,还有更多 - 例如它支持pattern matching(Java 没有)。 Scala 2.8 增加了命名参数和默认参数,用于为 case 类生成 copy method,它提供了与以下 Java 类的 with* 方法相同的功能。

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

那么,在使用中我们(当然)有:

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

反对

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

【讨论】:

  • 在 2.7.x 和 2.8.0 中,唯一的装箱是在 productElementsunapply 中,而不是在构造函数、字段或访问器中:gist.github.com/424375
  • 鼓励各种 getter/setter 不良行为。只能极不情愿地添加 Setter,仅在必要时才应添加 getter。添加“简单”如何导致不良习惯的好例子。
  • @Bill K:好的,那么我们将拥有case class Person(val firstName: String, val lastName: String) 那又怎样?也可以将其设为私有,但没有任何意义,因为 unapply 等。
  • @shiva case class Person(private val firstName: String),但那时你不应该使用案例类。相反,class Person(firstName: String)firstName 默认是私有的。
  • @shiva 没有。valprivate val 的区别在于访问器方法,即firstName()firstName(String),是公共的还是私有的。在 Scala 中,字段始终是私有的。为了让 Scala 生成 Java 风格的 get/set 方法(除了 Scala 风格的访问器),还有 @BeanProperty 注释。
【解决方案2】:

我觉得这个令人印象深刻

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

斯卡拉

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

还有这些(抱歉没贴,我不想偷代码)

【讨论】:

  • 这个 scala 代码不会生成 getFirstNamegetLastName 方法。您必须使用 scala.reflect.BeanProperty 注释来注释参数才能做到这一点。
  • @abhin4v:是的,但是 Scala 中的代码约定是没有以 get 为前缀的访问器。惯用的 Java 代码不同于惯用的 Scala 代码。有时 is 前缀用于布尔值。 davetron5000.github.com/scala-style/naming_conventions/methods/…
  • 您可以将其设为case class 并免费获得toStringequalshashCode(您也不必明确提出val 的参数): case class Person(firstName: String, lastName: String)
  • @shiva,为case class,而不仅仅是class
【解决方案3】:

任务:编写一个程序来索引关键字列表(如书籍)。

说明:

  • 输入:列表
  • 输出:地图>
  • 地图的关键是'A'到'Z'
  • 地图中的每个列表都已排序。

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

斯卡拉:

object Main extends App {
  val keywords = List("Apple", "Ananas", "Mango", "Banana", "Beer")
  val result = keywords.sorted.groupBy(_.head)
  println(result)
}

【讨论】:

  • 您可以使用 v.sorted 代替 (v sortBy identity)。
  • 在 Scala 2.8 中,您可以使用 mapValues (_.sorted) 代替 map { case ... }
  • 在 Java 8 中,代码几乎与 Scalas 相同:keywords.stream().sorted().collect(Collectors.groupingBy(it -> it.charAt(0)));成功了!
【解决方案4】:

任务:

您有一个 peoplePerson 的对象列表,其中包含字段 nameage。您的任务是先按name 排序此列表,然后按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());
  }
});

斯卡拉:

val sortedPeople = people.sortBy(p => (p.name, p.age))

更新

自从我写下这个答案以来,已经取得了相当大的进步。 lambda(和方法引用)终于登陆 Java,它们正在席卷 Java 世界。

这是上面的代码在 Java 8 中的样子(由@fredoverflow 提供):

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

虽然这段代码几乎一样短,但它的运行不如 Scala 优雅。

在 Scala 解决方案中,Seq[A]#sortBy 方法接受一个函数A =&gt; B,其中B 需要拥有一个OrderingOrdering 是一个类型类。两全其美:就像Comparable,它对于所讨论的类型是隐含的,但就像Comparator,它是可扩展的,并且可以追溯添加到没有它的类型。由于 Java 缺少类型类,它必须复制每个这样的方法,一次用于Comparable,然后用于Comparator。例如,请参阅 comparingthenComparing here

类型类允许编写规则,例如“如果 A 有排序而 B 有排序,那么它们的元组 (A, B) 也有排序”。在代码中,即:

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

这就是我们代码中的sortBy 可以按名称然后按年龄进行比较的方式。这些语义将使用上述“规则”进行编码。 Scala 程序员会直观地期望它以这种方式工作。无需将 comparing 等特殊用途的方法添加到 Ordering

Lambda 和方法引用只是函数式编程的冰山一角。 :)

【讨论】:

  • 缺少 lambdas(或至少是方法引用)是我在 Java 中缺少的最重要的特性。
  • @fredoverflow 感谢您添加 Java 8 示例。它仍然证明了为什么 Scala 的方法更胜一筹。稍后我会添加更多内容。
  • @rakemous,伙计,答案是六年前写的。
【解决方案5】:

任务:

您有一个如下所示的 XML 文件“company.xml”:

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

您必须阅读此文件并打印所有员工的firstNamelastName 字段。


Java: [取自here]

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: [取自 here,幻灯片 #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)
        } 
      }
    }
  }
}

[ 比尔编辑;检查 cmets 进行讨论]--

嗯,如何在未格式化的回复部分进行回复...哼。我想我会编辑你的答案,如果它打扰你,让你删除它。

这就是我在 Java 中使用更好的库的方式:

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

这只是一个没有魔法和所有可重用组件的快速破解。如果我想添加一些魔法,我可以做一些比返回字符串数组更好的事情,但即便如此,GoodXMLLib 也是完全可重用的。 scanFor的第一个参数是section,以后的参数都是要查找的item,有限制,但是界面可以稍微buff一下,增加多级匹配没问题。

我承认 Java 通常对库的支持很差,但是来吧——将 Java 十年(?)旧 XML 库的可怕用法与基于简洁的实现进行比较是不公平的——远非语言的比较!

【讨论】:

  • hmm,使用 SAX 或 StAX 解析器,Java 示例会更短且更好看。但是 SCALA 还是很不错的
  • Java 代码完全是为了解析特定的 XML 文件而编写的,没有尝试重用和大量重复的代码。写它的人要么故意装出他不懂编码或不懂编码的样子。
  • @Bill K:我从未在 Java 中进行过 XML 解析,所以我从某个随机站点中选择了这个示例。随意编辑答案的 Java 部分,我不介意。
  • 好吧,让我们假设您说的是语言差异而不是库差异——在这种情况下,两者几乎相同。第二个示例中唯一的语言差异是匹配/大小写的事情,如果由库以这种方式实现,则可以在一行中作为 for 循环完成。
  • @Bill K:不,你完全错了。这里有两个非常强大的 Scala 特性: 1. XML Literals 2. 模式匹配。 Java 没有这些。因此,在某些假设库中编写的等效 Java 代码肯定不会完全相同。 (试试写,你就知道了。)
【解决方案6】:

根据字符串执行的操作映射。

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

斯卡拉:

val todos = Map( "hi" -> { () => println("Good morning!") } )
val defaultFun = () => println("task not found")
todos.getOrElse("hi", defaultFun).apply()

这一切都以最好的口味完成!

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,我认为您的编辑不正确。 todos.get("hi") 返回 Option[()=&gt;Unit] 需要正确匹配。
  • @huynhjl,我的错。回滚。
  • 可以更短:val defaultFun = {() =&gt; println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
  • 甚至更短:val todos = Map("hi" -&gt; { () =&gt; println("Good morning!") }) withDefaultValue { () =&gt; println("task not found") } 然后todos("hi")()
【解决方案7】:

我喜欢这个简单的排序和转换示例,取自 David Pollak 的“Beginning Scala”一书:

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

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

【讨论】:

    【解决方案8】:

    我现在正在用 Scala 编写二十一点游戏。这是我的dealerWins 方法在Java 中的样子:

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

    这是它在 Scala 中的样子:

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

    高阶函数万岁!

    Java 8 解决方案:

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

    【讨论】:

    • scala 的语法非常困难。需要记住这么多:-(
    • Scala 就像 CSS,需要记住许多属性和属性
    • 更好:def dealerWins = !(players exists (_ beats dealer))
    【解决方案9】:

    快速排序怎么样?


    Java

    以下是通过google搜索找到的java示例,

    网址是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 版本的快速尝试。代码改进者的开放季节;@)

    def qsort(l: List[Int]): List[Int] = {
      l match {
        case Nil         => Nil
        case pivot::tail => qsort(tail.filter(_ < pivot)) ::: pivot :: qsort(tail.filter(_ >= pivot))
      }
    }
    

    【讨论】:

    • 链表上的快速排序是否具有 O(n^2) 时间复杂度?通常mergesort或类似的用于链表。
    • 它也不是尾递归的,因此不适合作为高性能算法(或不会溢出堆栈的算法)
    • 感谢有用的 cmets。我曾在某处看到过这样写的快速排序,它的紧凑性给我留下了深刻的印象,显然我没有过多考虑。我被 LOC 比较迷住了,这对于 Scala v Java 来说总是很诱人。
    • Quicksort 在函数列表上不是 O(n^2) 的,但它肯定有这种危险。渐近地,它仍然是平均 O(n log n),但是遇到最坏情况 O(n^2) 的统计概率更高,因为我们总是选择枢轴指向列表的头部,而不是随机选择一个。
    • 过滤两次不好。请参阅我对您问题的回答,使用 partition 来避免这种情况。
    【解决方案10】:

    我非常喜欢user unknown's answer,我将努力改进它。下面的代码不是对 Java 示例的直接翻译,但它使用相同的 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)
    }
    

    【讨论】:

    • 我现在还没有安装 scala-2.8 来测试这个 sn-p,但我想我可以看到什么是意图 - 根本没有使用“关键字”。它会生成所有字符串及其频率的映射,不是吗?
    • @user 是的,它就是这样做的。这不是你的代码完成的吗?哦,我明白了。我复制了错误的行。我马上去修。 :-)
    【解决方案11】:

    我非常喜欢 getOrElseUpdate 方法,在 mutableMap 中找到并在此处显示,首先是 Java,没有:

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

    是的 - WordCount,在 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
    }
    

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

    如果您想 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 已经显示,但看看它们与地图的集成是多么容易:

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

    【讨论】:

    • 我非常喜欢这个例子。它避免了比较案例类的简单方法,并且不会犯显示 Scala 代码而不是 Java 等价物的错误。
    【解决方案12】:

    这是一个非常简单的例子:整数平方然后相加

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

    在斯卡拉中:

    
    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)
    

    紧凑映射将函数应用于数组的所有元素,所以:

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

    向左折叠将以 0 作为累加器 (s) 开始,并将 add(s,i) 应用于数组的所有元素 (i),这样:

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

    现在可以进一步压缩为:

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

    这个我不会在 Java 中尝试(工作太多),将 XML 转换为 Map:

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

    另一个从 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)
    

    【讨论】:

    • 你在 Scala 中的 sumSquare 的问题在于它对 Java 开发人员来说看起来非常神秘,这会让他们有理由抱怨你 Scala 晦涩难懂和复杂......
    • 我重新格式化了一下以改进示例。希望这不会伤害 Scala。
    • scala> 1 到 10 映射 (x => x*x) sum res0: Int = 385 让我们看看 java 开发人员所说的神秘。那时它的手指在耳朵里说不,不,不。
    • @Jesper 对于非 Java 开发人员来说,Java 看起来像是大量的样板文件和线路噪音。这并不意味着您无法使用该语言完成真正的工作。
    • 您可以使用 reduceLeft(add) 代替 foldLeft(0)(add)。我认为当你的开始元素是组的零/身份元素时更容易阅读。
    【解决方案13】:

    问题:您需要设计一个异步执行任何给定代码的方法。

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

    Scala 中的相同内容(使用演员):

    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    
    }
    

    【讨论】:

    • 从 2.8 开始,这可以写为 Futures.future{body} 并且实际上更强大,因为它返回的未来可以被连接以获得它最终评估的值。
    【解决方案14】:

    Michael Nygard's Release It 中的断路器模式 FaKods (link to code)

    在 Scala 中的实现如下所示:

    . . .
    addCircuitBreaker("test", CircuitBreakerConfiguration(100,10))
    . . .
    
    
    class Test extends UsingCircuitBreaker {
      def myMethodWorkingFine = {
        withCircuitBreaker("test") {
          . . .
        }
      }
    
      def myMethodDoingWrong = {
        withCircuitBreaker("test") {
          require(false,"FUBAR!!!")
        }
      }
    }
    

    我认为这非常好。它看起来只是语言的一部分,但它是CircuitBreaker Object 中的一个简单混合,可以完成所有工作。

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

    其他语言的 Google 参考“断路器”+ 您的语言。

    【讨论】:

      【解决方案15】:

      我正在准备一份文档,其中提供了几个 Java 和 Scala 代码示例,仅利用了 Scala 简单易懂的特性:

      Scala : A better Java

      如果您希望我添加一些内容,请在 cmets 中回复。

      【讨论】:

      • 标题“Scala:更好的 Java”具有误导性
      【解决方案16】:

      延迟评估的无限流就是一个很好的例子:

      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 中无限流的问题:Is an infinite iterator bad design?

      另一个很好的例子是一流的函数和闭包:

      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 不支持第一类函数,并且使用匿名内部类模仿闭包不是很优雅。这个例子表明java不能做的另一件事是从解释器/REPL运行代码。我发现这对于快速测试代码 sn-ps 非常有用。

      【讨论】:

      • 请注意筛子太慢,不实用。
      • @oxbow_lakes 这些示例没有等效的 java。
      • @dbyme 不正确。您可以轻松地继承 Java 的 IterableIterator 以生成无限流。
      • @dbyrne “这个例子表明 java 不能做的另一件事是从解释器/REPL 运行代码。我发现这对于快速测试代码 sn-ps 非常有用。”我在 Eclipse 中使用剪贴簿页面来试用 Java sn-ps。在那个 IDE 中完成大部分(如果不是全部)Java 工作,我不需要 REPL。我在早期使用 notepad.exe 和 javac,当时我不确定一种语言或库功能,并且在很短的时间内运行得非常好和快速 - 尽管 REPL 更容易使用 - 而且速度更快。我可以通过安装我们已经在其中的 VisualAge 来完全避免记事本黑客攻击
      【解决方案17】:

      为什么以前没有人发过这个:

      Java:

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

      116 个字符。

      斯卡拉:

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

      56 个字符。

      【讨论】:

      【解决方案18】:

      这个 Scala 代码...

      def partition[T](items: List[T], p: (T, T) => Boolean): List[List[T]] = {
        items.foldRight[List[List[T]]](Nil)((item: T, items: List[List[T]]) => items match {
          case (first :: rest) :: last if p (first, item) =>
            (List(item)) :: (first :: rest) :: last
          case (first :: rest) :: last =>
            (item :: first :: rest) :: last
          case _ => List(List(item))
        })
      }
      

      ...如果可能的话,在 Java 中将完全不可读。

      【讨论】:

      • 我的正确意见:感谢您的回答!但你能解释一下那里发生了什么吗?我还不熟悉 Scala 语法,而且(这就是可能的原因)即使现在对我来说它看起来也完全不可读。
      • 它使用提供的分区函数作为 case 语句的模式匹配子句中的保护来对类型 T 的通用列表进行分区。
      • 很奇怪。我什至不是 Scala 专家,但我可以弄清楚。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-11
      • 1970-01-01
      • 2016-06-21
      相关资源
      最近更新 更多