Scala代码看起来更简单/更少行的Scala和Java代码示例?

Samples of Scala and Java code where Scala code looks simpler/has fewer lines?

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

如果只有Scala样的评论,比如"这是在斯卡拉的抽象工厂,在Java中它看起来会更麻烦",那么这也是可以接受的。

谢谢!

我最喜欢被接受的答案


让我们改进Stacker的示例并使用scala的case类:

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

上面的Scala类包含下面的Java类的所有特性,还有一些,例如,它支持模式匹配(Java没有这样的模式)。Scala 2.8添加了命名和默认参数,这些参数用于生成CASE类的复制方法,提供与下面Java类的方法相同的能力。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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 +")";
    }
}

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

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

反对

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


我觉得这个令人印象深刻

爪哇

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
    }
}

斯卡拉

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

还有这些(不好意思没有粘贴,我不想偷代码)

  • 皇后问题
  • 皇后区问题斯卡拉


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

说明:

  • 输入:list
  • 输出:map>
  • 地图的关键是"a"到"z"
  • 对地图中的每个列表进行排序。

爪哇:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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);        
  }
}

斯卡拉:

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


任务:

您有一个包含字段nameagepeople类对象的列表。您的任务是先按name对该列表进行排序,然后按age对其进行排序。

Java 7:

1
2
3
4
5
6
7
8
9
10
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());
  }
});

斯卡拉:

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

号更新

自从我写下这个答案以来,已经有了很大的进步。LAMBDAS(和方法参考)终于登陆爪哇,他们正在攻占爪哇世界。

这是上面代码与Java 8(由@ FrdodoFLUW提供的)类似的代码:

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

虽然这段代码几乎和scala代码一样短,但它的工作却没有scala代码那么优雅。

在scala解决方案中,Seq[A]#sortBy方法接受一个函数A => B,其中B需要有一个OrderingOrdering是一个类型类。最好考虑两个方面:像Comparable一样,它是隐式的,但像Comparator一样,它是可扩展的,可以追溯地添加到没有它的类型中。由于Java缺少类型类,所以必须复制每个这样的方法,一次用于EDCOX1,15个,然后为EDCOX1,16个。例如,请参见此处的comparingthenComparing

类型类允许我们编写规则,比如"如果a有排序,b有排序,那么它们的元组(a,b)也有排序"。在代码中,即:

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

这就是我们代码中的sortBy如何按名称和年龄进行比较。这些语义将使用上述"规则"进行编码。一个scala程序员会直观地期望这个方法是这样工作的。不必在Ordering中添加像comparing这样的特殊目的方法。

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


任务:

您有一个XML文件"company.xml",它如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0"?>
<company>
   
        <firstname>Tom</firstname>
        <lastname>Cruise</lastname>
    </employee>
   
        <firstname>Paul</firstname>
        <lastname>Enderson</lastname>
    </employee>
   
        <firstname>George</firstname>
        <lastname>Bush</lastname>
    </employee>
</company>

您必须阅读此文件并打印所有员工的firstNamelastName字段。爪哇:[从这里夺走]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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();
    }
  }
}

斯卡拉:【从这里开始,幻灯片19】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import xml.XML

object XmlReader {
  def main(args: Array[String]): Unit = {
    XML.loadFile("company.xml") match {
      case  { employees @ _* } </employee> => {
        for(e <- employees) {
          println("First Name:" + (e "firstname").text)
          println("Last Name:" + (e "lastname").text)
        }
      }
    }
  }
}

[按比尔编辑;检查讨论的评论]--

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

这就是我如何在Java中使用更好的库:

1
2
3
4
5
6
7
8
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的第一个参数是该部分,所有未来的参数都是要查找的有限项,但是界面可以稍微抛光,以添加多个匹配级别,没有真正的问题。

我承认Java一般有一些很差的库支持,但是来比较一下Java十年的可怕用法(?)旧的XML库对一个基于简洁的实现来说是不公平的——而且远不是语言的比较!


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

Java 7:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 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");

斯卡拉:

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

而且都是以最好的口味做的!

Java 8:

1
2
3
4
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();


我现在在斯卡拉写21点游戏。下面是我的DealErrWin方法在Java中的用法:

1
2
3
4
5
6
boolean dealerWins() {
    for(Player player : players)
        if (player.beats(dealer))
            return false;
    return true;
}

以下是斯卡拉的情况:

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

高次功能万岁!

Java 8解决方案:

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


我喜欢这个简单的排序和转换示例,摘自大卫·波拉克的《开始的斯卡拉》一书:

在scala中:

1
2
3
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中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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)

我非常喜欢"未知用户"的答案,所以我会努力改进它。下面的代码不是Java实例的直接翻译,而是用相同的API完成相同的任务。

1
2
3
4
5
6
7
8
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)
}


我非常喜欢在MutabLimAP中找到的GETORESeLoad方法,并在这里显示,第一个Java,没有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}

是的-一个字数,在scala中:

1
2
3
4
5
6
7
8
9
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:

1
2
3
4
5
6
7
8
9
10
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%发挥作用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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已经显示出来了,但是看看它们与地图集成有多简单:

1
2
3
4
    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)
    }


快点怎么样?

爪哇

下面是通过谷歌搜索找到的Java示例,

网址是http://www.mycstutorials.com/articles/sorting/quicksort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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版本的快速尝试。代码改进程序的开放季节;@)

1
2
3
4
5
6
def qsort(l: List[Int]): List[Int] = {
  l match {
    case Nil         => Nil
    case pivot::tail => qsort(tail.filter(_ < pivot)) ::: pivot :: qsort(tail.filter(_ >= pivot))
  }
}


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

Java解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 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中也是这样(使用actors):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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    
}


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

1
2
3
4
5
6
7
    public int sumSquare(int[] list) {
        int s = 0;
        for(int i = 0; i < list.length; i++) {
            s += list[i] * list[i];
        }
        return s;
    }

在scala中:

1
2
3
4
5
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)

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

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

fold left将以0作为累加器开始,并将add(s,i)应用于数组的所有元素(i),以便:

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

现在可以进一步压缩到:

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

这一个我不会在Java中尝试(大量工作),将XML转换成地图:

1
2
   <b id="a10">Scala
   <b id="b20">rules

另一个从XML获取映射的一行程序:

1
2
3
4
5
val xml = <b id="a10">Scala<b id="b20">rules

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中实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
. . .
addCircuitBreaker("test", CircuitBreakerConfiguration(100,10))
. . .


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

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

我觉得非常好。它看起来就像一幅语言的图片,但它只是一个简单的电路断路器对象中的混合,可以完成所有工作。

1
2
3
4
5
6
7
8
9
10
/**
 * Basic MixIn for using CircuitBreaker Scope method
 *
 * @author Christopher Schmidt
 */

trait UsingCircuitBreaker {
  def withCircuitBreaker[T](name: String)(f: => T): T = {
    CircuitBreaker(name).invoke(f)
  }
}

其他语言的参考谷歌"断路器"+你的语言。


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

爪哇:

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

116个字符。

斯卡拉:

1
2
3
object Hello extends App {
     println("Hello world")
}

56个字符。


我正在准备一个文档,它给出了Java和Scala代码的几个例子,只使用了简单的理解斯卡拉的特性:

斯卡拉:一个更好的Java

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


延迟计算的无限流就是一个很好的例子:

1
2
3
4
5
6
7
8
9
10
11
12
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中无限流的问题:无限迭代器是不是坏的设计?

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

1
2
3
4
5
6
7
8
9
10
11
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中运行代码。我发现这对于快速测试代码片段非常有用。


这个scala代码…

1
2
3
4
5
6
7
8
9
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中是完全不可读的。