Scalaコードがより単純に見える/行が少ないScalaおよびJavaコードのサンプル?


94

ScalaコードがJavaで書かれたコードよりもシンプルで簡潔であることを示す、ScalaおよびJavaコードのコードサンプルがいくつか必要です(私はそれらについても興味があります)(もちろん、両方のサンプルで同じ問題を解決できるはずです)。

「これはScalaの抽象ファクトリです。Javaではもっと面倒に見えます」のようなコメント付きのScalaサンプルしかない場合は、これも許容されます。

ありがとう!

私は受け入れられたすべての中で最も好きであり、この答え


3
少しの手間
nicerobot

4
この種の質問で正しい答えが1つあるのはなぜですか。
polygenelubricants 2010年

@polygenelubricants:そして、あなたが提案するものは?
ローマン

10
@Roman:Scalaがより簡潔になることを期待しています。ScalaよりもJavaでより簡潔に表現されたものを見つけることができれば、もっと興味深いでしょう。
Randall Schulz

1
@Randall Schulz:Scalaの方が簡潔であることは誰もが知っていますが、場合によっては、学術目的のために、例と背景理論を用いた証明が必要です。
ローマン

回答:


76

スタッカーの例を改善して、Scalaのケースクラスを使用してみましょう。

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

Scalaのクラス以上以下のJavaクラスのすべての機能が含まれている、といくつかのより多くの -例えば、それがサポートしているパターンマッチング(Javaはありません)。Scala 2.8は、名前付きおよびデフォルトの引数を追加します。これらは、ケースクラスのコピーメソッドを生成するために使用されます。これにより、次の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
2.7.xおよび2.8.0では、ボクシングはコンストラクター、フィールド、またはアクセサーではなく、productElementsおよびにのみありunapplyます:gist.github.com/424375
retronym

2
あらゆる種類のゲッター/セッターの悪さを助長します。セッターは極端に不本意ながら追加する必要があります。ゲッターは必要な場合にのみ追加してください。「シンプルさ」を追加することが悪い習慣につながる良い例。
ビルK

7
@ビルK:わかりまし case class Person(val firstName: String, val lastName: String) た。事のプライベートがあまりにも可能でしょうが、理由適用を解除するなどの、任意の意味をなさないことを作る
SOC

1
@shiva case class Person(private val firstName: String)、しかしケースクラスを使うべきではありません。代わりに行うclass Person(firstName: String)firstName、デフォルトではプライベートです。
nilskp 2013

1
@shiva番号の差valとは、private valアクセサメソッドかどうか、すなわちことであるfirstName()firstName(String)、パブリックまたはプライベートです。Scalaではフィールドは常にプライベートです。Scalaが(Scalaスタイルのアクセサーに加えて)Javaスタイルのget / setメソッドを生成するために、@BeanPropertyアノテーションがあります。
Esko Luontola 2013

45

これは印象的だと思いました

ジャワ

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)

これらのものと同様に(貼り付けられなかったため申し訳ありませんが、コードを盗みたくありませんでした)


このScalaコードはメソッドgetFirstNamegetLastNameメソッドを生成しません。これscala.reflect.BeanPropertyを行うには、パラメータに注釈を付ける必要があります。
Abhinav Sarkar

7
@ abhin4v:はい。ただし、Scalaのコード規約では、接頭辞がget。慣用的なJavaコードは、慣用的なScalaコードとは異なります。時には、isブール値のために使用される接頭辞。davetron5000.github.com/scala-style/naming_conventions/methods/...
エスコLuontola

6
あなたはそれを作ることができるcase classと取得toStringequalsおよびhashCode自由のための(そして、あなたはまた、引数を加える必要はありませんval:明示的)case class Person(firstName: String, lastName: String)
ジェスパー

@shiva、のためcase classだけでなく、のためclass
nilskp 2013

23

タスク:キーワードのリスト(本など)に索引を付けるプログラムを作成します。

説明:

  • 入力:リスト<文字列>
  • 出力:Map <Character、List <String >>
  • マップのキーは「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);         
  }
}

Scala:

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

(v sortBy identity)の代わりにv.sortedを使用できます。
Eastsun

1
また、Scala 2.8では、map {case ...}の代わりにmapValues(_.sorted)を使用できます
Alex Boisvert

10
Java 8では、コードはScalasとほぼ同じです。keywords.stream()。sorted()。collect(Collectors.groupingBy(it-> it.charAt(0))); トリックを行います!
コーディネーター

11

仕事:

フィールドとを持つpeopleクラスのオブジェクトのリストがあります。あなたの仕事は、このリストをまずでソートし、次にでソートすることです。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))

更新

この回答を書いてから、かなりの進歩がありました。ラムダ(およびメソッド参照)がついにJavaに上陸し、Javaの世界を席巻しました。

これは、Java 8で上記のコードがどのように見えるかです(@fredoverflowによって提供されます)。

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

このコードはほとんど同じですが、Scalaのコードほどエレガントには機能しません。

Scalaの溶液中に、Seq[A]#sortBy本方法は、機能受け付けるために必要とされる持っています。型クラスです。両方の世界のベストを考える:のように、それは問題の型に対して暗黙的ですが、のように拡張可能であり、それがなかった型に遡及的に追加できます。Javaには型クラスがないため、そのようなメソッドをすべて複製しなければなりません。たとえば、およびこちらを参照してくださいA => BBOrderingOrderingComparableComparatorComparableComparatorcomparingthenComparing

型クラスを使用すると、「Aに順序付けがあり、Bに順序付けがある場合、タプル(A、B)にも順序付けがある」などのルールを記述できます。コードでは、次のとおりです。

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

このようにsortByして、コード内のを名前で、次に年齢で比較できます。これらのセマンティクスは、上記の「ルール」でエンコードされます。Scalaプログラマーは、これがこのように機能することを直感的に期待します。などの特別な目的のメソッドcomparingをに追加する必要はありませんでしたOrdering

ラムダとメソッド参照は、関数型プログラミングである氷山の一角にすぎません。:)


ラムダ(または少なくともメソッド参照)の欠落は、Javaで欠けている最も重要な機能です。
Petr Gladkikh、2011

@fredoverflow Java 8の例を追加していただきありがとうございます。それでも、Scalaのアプローチが優れている理由が示されています。後で追加します。
missingfaktor 2015年

@rakemous、仲間、答えは6年以上前に書かれました。
missingfaktor 16

10

仕事:

次のような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>

このファイルを読み取り、全従業員のfirstNameおよびlastNameフィールドを印刷する必要があります。


Java: [ ここから取得]

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: [ ここから抜粋、スライド#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)
        } 
      }
    }
  }
}

[ビルによる編集; ディスカッションのコメントを確認してください]-

うーん、フォーマットされていない返信セクションで返信せずにそれを行う方法... Hmph。私はあなたの答えを編集し、それがあなたを悩ませている場合はあなたにそれを削除させると思います。

これは、より良いライブラリを使用して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の最初のパラメーターはセクションです。今後のすべてのパラメーターは、検索対象のアイテムであり、制限がありますが、インターフェースをわずかに強化して、実際の問題なしに複数レベルのマッチングを追加できます。

Javaには一般的にかなり貧弱なライブラリサポートがあることを認めますが、Javaの10年前の恐ろしい使用法(?)の古いXMLライブラリを簡潔に基づいて行われた実装と比較するのは公平ではありません-はるかに言語の比較から!


うーん、Javaの例はSAXまたはStAXパーサーを使用すると短くて見栄えがよくなります。しかし、それでもSCALAは本当に素晴らしいです
oluies

5
Javaコードは、特定のXMLファイルを正確に解析するように記述されており、再利用を試みたり、多くの重複したコードを作成したりすることはありません。それを書いた人は、故意にコーディングを理解していないか、コーディングを理解していないように見せようとしているのです。
ビルK

@Bill K:私はJavaでXML解析を行ったことがないので、この例をランダムなサイトから選びました。答えのJava部分を自由に編集してください。私は気にしません。
missingfaktor

さて、あなたが話しているのは言語の違いであり、ライブラリの違いではないと仮定しましょう。その場合、2つはほぼ同じになります。2番目の例の唯一の言語の違いは、ライブラリによってそのように実装された場合、forループとして単一行で実行できる一致/ケースのことです。
ビルK

@ビルK:いいえ、あなたは完全に間違っています。ここには2つの非常に強力なScala機能があります。1。XMLリテラル2.パターンマッチング。Javaにはこれらのいずれもありません。したがって、いくつかの架空のライブラリで記述された同等のJavaコードは、確実に同一ではありません。(書いてみてください。わかります。)
missingfaktor

10

文字列に応じて実行するアクションのマップ。

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

そしてそれはすべて可能な限り最高の味で行われます!

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[()=>Unit]ます。
huynhjl

@huynhjl、私の悪い。元に戻しました。
missingfaktor

3
さらに短くすることもできます:val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
Geoff Reedy、2010年

2
さらに短く:val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }その後todos("hi")()
マーティンリング

8

私は現在Scalaでブラックジャックゲームを書いています。これが私のディーラーウィンズメソッドが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には非常に難しい構文があります。そんなに覚える必要があります:-(
AZ_

ScalaはCSSのようなものであり、覚えておくべき多くの属性やプロパティに対応しています
AZ_

1
良い:def dealerWins = !(players exists (_ beats dealer))
ケビンライト

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)

6

クイックソートはどうですか?


ジャワ

以下はグーグル検索で見つかったJavaの例です、

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バージョンの簡単な試み。コード改善者のためのオープンシーズン; @)

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
リンクされたリストのクイックソートはO(n ^ 2)時間の複雑さを持っていますか?通常、リンクリストにはマージソートなどが使用されます。
Esko Luontola

3
また、末尾再帰ではないため、パフォーマンスアルゴリズム(またはスタックをオーバーフローしないアルゴリズム)としては不適切です
oxbow_lakes

有用なコメントをありがとう。このようなクイックソートをどこかで見たことがありますが、そのコンパクトさには感心しました。LOCの比較に夢中になりました。LOCの比較は、常にScala v Javaの魅力的なものです。
Don Mackenzie

2
クイックソートは関数リストではO(n ^ 2)ではありませんが、確かにその危険があります。漸近的には、それでも平均O(n log n)ですが、ピボットポイントをランダムに選択するのではなく、常にリストの先頭にあるピボットポイントを選択するため、最悪のケースO(n ^ 2)にヒットする統計的確率が高くなります。 。
Daniel Spiewak

2回のフィルタリングは適切ではありません。あなたの質問に対する私の回答で、partitionそれを回避するための使用を参照してください。
ダニエルC.ソブラル

6

user unknownの 回答が気に入ったので、それを改善しようと思います。以下のコードは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をインストールしていませんが、意図しているものはわかると思います。「キーワード」はまったく使用されていません。すべての文字列とその頻度のマップを作成しますね。
ユーザー不明。

@userはい、そうです。それはあなたのコードによって何が成し遂げられたのではないでしょうか?ああなるほど。間違った行をコピーしました。今直します。:-)
ダニエルC.ソブラル

6

mutableMapにあり、ここに示されているgetOrElseUpdateメソッドが好きです。

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

filterそしてsort、既に示されているが、外観はどのように簡単にそれらがマップに統合されています。

    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の同等のコードを表示するのを間違えません。
ダニエルC.ソブラル2010年

5

これは非常に単純な例です:整数を平方してから追加します


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

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)

コンパクトマップは、関数を配列のすべての要素に適用するため、次のようになります。

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

左折は、アキュムレータとして0で始まり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をマップに変換します。


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

XMLからマップを取得するもう1つのライナー:


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)

sumSquareScala でのあなたの問題は、Java開発者にとって非常に謎めいているように見えることです。これにより、Scalaが不明瞭で複雑であると不平を言う彼らに対して弾薬が与えられます...
Jesper

私は例を改善するために少し再フォーマットしました。これがScalaを傷つけないことを願っています。
Thomas

5
scala> 1から10までのマップ(x => x * x)sum res0:Int = 385 Java開発者がその不可解な呼び出しを見てみましょう。その時点では、耳に指があり、nah-nah-nahと言っています。
psp

3
@Jesper Java以外の開発者にとって、Javaは大量の定型文やラインノイズのように見えます。その言語で実際の仕事ができないという意味ではありません。
James Moore

foldLeft(0)(add)の代わりにreduceLeft(add)を使用できます。開始要素がグループのzero / identity要素であると、読みやすくなります。
Debilski

5

問題:任意のコードを非同期で実行するメソッドを設計する必要があります。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    
}

6
2.8以降、これはFutures.future {body}として記述でき、これによって返されるフューチャーを結合して最終的に評価される値を取得できるため、実際にはより強力です。
デイブグリフィス

3

サーキットブレーカーパターンマイケルNygårdののリリースこれFaKodsコードへのリンク

Scalaでの実装は次のようになります。

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


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

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

とてもいいと思います。それは言語のほんの一部のように見えますが、すべての作業を行うCircuitBreakerオブジェクトの単純なミックスインです。

/**
 * 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の他の言語での「回路ブレーカー」とあなたの言語の参照。


3

Scalaの理解しやすい機能のみを利用して、JavaおよびScalaコードのいくつかの例を示すドキュメントを準備しています。

Scala:より良いJava

何か追加したい場合は、コメントで返信してください。


タイトル「Scala:a better Java」は誤解を招く
duckhunt

2

以前誰もこれを投稿しなかった理由:

Java:

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

116文字。

Scala:

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

56文字。


1
Application有害と考えられた形質... scala-blogs.org/2008/07/...
missingfaktor

1

遅延評価される無限ストリームが良い例です:

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つの良い例は、ファーストクラスの関数とクロージャーです。

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はファーストクラスの機能をサポートしていないため、匿名の内部クラスでクロージャを模倣することはあまりエレガントではありません。この例が示しているもう1つのことは、Javaが実行できないことは、インタープリター/ REPLからコードを実行することです。これは、コードスニペットをすばやくテストするのに非常に便利です。


ふるいは遅すぎて実用的でないことに注意してください。
Elazar Leibovich

@oxbow_lakesこれらの例に相当するJavaはありません。
dbyrne

@dbyme真実ではない。Javaを簡単にサブクラス化IterableIteratorて、無限のストリームを生成できます。
Daniel C. Sobral

@dbyrne「この例が示しているもう1つのことは、javaが実行できないことは、インタプリタ/ REPLからコードを実行することです。これは、コードスニペットをすばやくテストするのに非常に役立ちます。」Javaスニペットを試すために、Eclipseのスクラップブックページを使用しています。そのIDEですべてのJavaが機能するとは限りませんが、ほとんどの場合、REPLは必要ありません。言語やライブラリの機能がわからなかった初期の頃は、notepad.exeとjavacを使用していました。しばらくすると、REPLの方が多少使いやすく、高速になりましたが、非常にうまく高速に動作しました。私たちはすでに持っていたのVisualAgeインストールすることで、完全にメモ帳のハックを避けたかもしれない

0

この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で完全に読み取ることはできません。


10
私の正しいオピニオ:答えてくれてありがとう!しかし、そこで何が起こるか説明してもらえますか?私はまだScala構文に慣れていないので、(それが理由である可能性があるため)、今でも完全に読めないように見えます。
ローマン

これは、Caseステートメントのパターンマッチング句のガードとして提供されているパーティション関数を使用して、タイプTのジェネリックリストをパーティション分割します。
私の正しい意見だけ

3
変だ。私は、Scalaのエキスパートでもありません。
私の正しい意見だけ正しい
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.