Зразки коду Scala та Java, де код Scala виглядає простішим / має менше рядків?


94

Мені потрібні деякі зразки коду (і мені це дуже цікаво) коду Scala та Java, які показують, що код Scala є більш простим та стислим, ніж код, написаний на Java (звичайно, обидва зразки повинні вирішувати одну і ту ж проблему).

Якщо є лише зразок Scala з коментарем на кшталт "це абстрактна фабрика в Scala, на Java це буде виглядати набагато громіздкіше", то це також прийнятно.

Дякую!

Мені найбільше подобається прийняте і це відповіді


3
З невеликою роботою на ногах ви можете знайти безліч зразків на rosettacode.org
nicerobot

4
Як у такому питанні може бути одна правильна відповідь?
полігенмастильні матеріали

@polygenelubricants: а що ви пропонуєте?
Роман

10
@ Роман: Ми очікуємо, що Scala буде більш лаконічним. Було б цікавіше, якби ви могли знайти щось більш чітко виражене на Яві, ніж у Скалі.
Randall Schulz

1
@Randall Schulz: всі знають, що Scala є більш стислим, але іноді в академічних цілях нам потрібні докази з прикладами та основними теоріями.
Роман

Відповіді:


76

Давайте вдосконалимо приклад стекера та скористаємось класами кейсів Scala :

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

Вищезазначений клас Scala містить усі функції нижчого класу Java, а також деякі інші - наприклад, він підтримує узгодження шаблонів (яких у Java немає). Scala 2.8 додає іменовані та аргументи за замовчуванням, які використовуються для створення методу копіювання для класів регістрів, який надає ті самі можливості, що і методи * з наступного класу Java.

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не в конструкторі, полі чи доступі
ретронім

2
Заохочує всілякі недоброзичливці. Сеттери слід додавати лише з крайнім небажанням, геттери слід додавати лише за необхідності. Хороший приклад того, як додавання "простоти" веде до шкідливих звичок.
Білл К

7
@Bill 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

1
@shiva No. Різниця між valта private valполягає в тому, чи є методи доступу, тобто firstName()і firstName(String), відкритими чи приватними. У Scala поля завжди приватні. Для Scala для генерації методів get / set у стилі Java (на додаток до стилів Scala) існує @BeanPropertyанотація.
Еско Луонтола

45

Я знайшов це вражаюче

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)

Як і ці (вибачте, що не вставляли, я не хотів красти код)


Цей шкала-код не буде генерувати getFirstNameта getLastNameметоди. Для цього вам потрібно анотувати параметри за допомогою scala.reflect.BeanPropertyанотації.
Абхінав Саркар

7
@ abhin4v: Так, але домовленість коду в Scala полягає в тому, щоб не мати доступу з префіксом get. Ідіоматичний код Java відрізняється від ідіоматичного коду Scala. Іноді isпрефікс використовується для булів. davetron5000.github.com/scala-style/naming_conventions/methods/…
Еско Луонтола

6
Ви можете зробити це case classі отримати toString, equalsі hashCodeбезкоштовно (і вам також не потрібно valчітко case class Person(firstName: String, lastName: String)
наводити

@shiva, бо case classне просто class.
nilskp

23

Завдання: Написати програму для індексації списку ключових слів (наприклад, книг).

Пояснення:

  • Введення: Список <String>
  • Вихідні дані: Карта <Символ, Список <Рядок>>
  • Ключ карти - від "А" до "Я"
  • Кожен список на карті відсортований.

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. Sorted замість (v sortBy identity).
Eastsun

1
А в Scala 2.8 ви можете використовувати mapValues ​​(_.orted) замість map {case ...}
Alex Boisvert 02

10
У Java 8 код майже ідентичний Scalas: Keywords.stream (). Sorted (). Collection (Collectors.groupingBy (it -> it.charAt (0))); робить трюк!
Координатор

11

Завдання:

У вас є список peopleоб'єктів класу, у Personяких є поля nameта age. Ваше завдання - сортувати цей список спочатку 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());
  }
});

Scala:

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

Оновлення

З того часу, як я написав цю відповідь, було досягнуто певного прогресу. Лямбди (та методичні посилання) нарешті висадилися на Яві, і вони штурмують світ Яви.

Ось як виглядатиме наведений вище код у Java 8 (надає @fredoverflow):

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

Хоча цей код майже такий короткий, він працює не так елегантно, як у Scala.

У розчині Scala, то Seq[A]#sortByметод приймає функцію , A => Bде Bпотрібно , щоб матиOrdering . Orderingце тип-клас. Подумайте найкраще з обох світів: Мовляв Comparable, це неявно для відповідного типу, але, схоже Comparator, він розширюваний і може бути доданий ретроспективно до типів, яких у нього не було. Оскільки Java не має класів типів, вона повинна дублювати кожен такий метод, раз для Comparable, потім для Comparator. Наприклад, дивіться comparingі thenComparing тут .

Класи типів дозволяють писати правила типу "Якщо A має впорядкування, а B - впорядкування, то їх кортеж (A, B) також має впорядкування". У коді, тобто:

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

Ось як sortByв нашому коді можна порівняти за іменем, а потім за віком. Ця семантика буде закодована за допомогою вищезазначеного "правила". Програміст Scala інтуїтивно очікував, що це буде працювати таким чином. Жодних спеціальних методів, таких як comparingдоводилося додавати Ordering.

Ламбдас і методичні посилання - лише підказка айсберга, що є функціональним програмуванням. :)


Відсутність лямбда (або принаймні посилання на метод) - найважливіша особливість, яку я сумую в Java.
Петр Гладких

@fredoverflow Дякуємо за додавання прикладу Java 8. Це все ще демонструє, чому підхід Scala вищий. Додам ще пізніше.
missingfaktor

@rakemous, товаришу, відповідь була написана більше шести років тому.
missingfaktor

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



Скала: [взято звідси , слайд №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 від Білла; Перевірте коментарі для обговорення] -

Хм, як це зробити, не відповідаючи в розділі з неформатною відповіддю ... Гмм. Я думаю, я відредагую вашу відповідь і дозволю вам видалити її, якщо вона вас хвилює.

Ось як я це зробив би в 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 загалом є досить бідна підтримка бібліотеки, але давай - порівняти жахливе використання старої бібліотеки XML (?) Десятиліття Java з реалізацією, зробленою на основі короткого терміну, просто не чесно - і далеко зі порівняння мов!


хм, приклад Java був би коротшим і краще виглядає за допомогою аналізатора SAX або StAX. Але все-таки SCALA - це справді приємно
олюї

5
Код Java написаний саме для розбору конкретного XML-файлу без спроби повторного використання та безлічі дублюваних кодів. Хто б це не написав, намагався навмисно виглядати так, ніби він не розуміє кодування, або не розуміє кодування.
Білл К

@Bill K: Я ніколи не робив XML-розбір на Java, тому вибрав цей приклад з якогось випадкового сайту. Не соромтеся редагувати частину відповіді на Java, я не проти.
missingfaktor

Ну, припустимо, що ви говорите на мовних відмінностях, а не на бібліотечних відмінностях - у такому випадку вони були б майже однаковими. Єдиною мовною різницею у другому прикладі є відповідність / випадок, що може бути виконано в одному рядку як цикл for, якщо це реалізовано бібліотекою.
Білл К

@Bill K: Ні, ви абсолютно помиляєтесь. Тут працюють дві дуже потужні функції Scala: 1. XML Literals 2. узгодження зразків. У Java немає жодного з них. Тож еквівалентний код Java, записаний у певній гіпотетичній бібліотеці, точно не буде ідентичним. (Спробуйте написати, ви знаєте.)
пропав фактор

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, погано. Відкотив його назад.
зниклий фактор

3
Може бути ще коротшим:val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
Geoff Reedy

2
Ще коротше: val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }а потімtodos("hi")()
Мартін Рінг

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 має дуже складний синтаксис. потрібно пам'ятати так багато :-(
AZ_

Scala схожа на CSS, багатьом атрибутам та властивостям, які потрібно пам’ятати
AZ_

1
краще:def dealerWins = !(players exists (_ beats dealer))
Кевін Райт

7

Мені сподобався цей простий приклад сортування та перетворення, взятий із книги «Початок Скали» Девіда Поллака:

У 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

Як щодо Quicksort?


Java

Нижче наведено приклад java, знайдений за допомогою google search,

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. Відкритий сезон для поліпшень коду; @)

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) чи ні? Зазвичай злиття або подібне використовується для пов'язаних списків.
Еско Луонтола

3
Це також не рекурсивний хвіст, а тому непридатний як алгоритм виконавця (або той, який не переповнить стек)
oxbow_lakes

Дякую за корисні коментарі. Я десь бачив, як тут писали цю швидку сорту, і мене вразила її компактність, явно не надто роздумував над цим. Мене захопило порівняння LOC, яке завжди є спокусливою справою в Scala v Java.
Дон Макензі

2
Швидкий сорт не є O (n ^ 2) у функціональних списках, але він, безумовно, має таку небезпеку. Асимптотично, це все ще середнє значення O (n log n) , але існує більша статистична ймовірність потрапляння в найгірший випадок O (n ^ 2), оскільки ми завжди вибираємо точку зрізу на початку списку, а не вибираємо одну навмання .
Даніель Шпієк

Двічі фільтрувати - це погано. Дивіться в моїй відповіді на ваше запитання, як цього partitionуникнути.
Daniel C. Sobral

6

Мені сподобався невідомий користувач в відповідь так багато , я буду намагатися поліпшити його. Наведений нижче код не є прямим перекладом прикладу 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 для тестування цього фрагмента, але, мабуть, я бачу, що таке intendet - просто «ключові слова» взагалі не використовуються. Він створює карту всіх рядків та їх частот, чи не так?
користувач невідомий

@user Так, це робиться. Хіба це не є вашим кодом? О Я бачу. Я скопіював неправильний рядок. Я зараз це виправлю. :-)
Даніель К. Собрал

6

Мені дуже подобається метод 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, і ось у масштабі:

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.
Даніель К. Собрал

5

Це дуже простий приклад: квадратні цілі числа, а потім додайте їх


    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 як акумулятор (и) і застосовуватиметься 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:


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)

Проблема з вашою sumSquareпрограмою Scala полягає в тому, що вона здається дуже загадковою для розробника Java, який дасть їм патрони проти вас, щоб скаржитися на те, що Scala є неясною та складною ...
Jesper

Я трохи переформатував, щоб покращити приклад. Сподіваюся, що це не зашкодить Скалі.
Томас

5
масштаб> від 1 до 10 карти (x => x * x) сума res0: Int = 385 Давайте подивимось, як розробник Java називає це загадковим. У цей момент пальці у вухах говорять нах-нах-нах.
psp

3
@Jesper Для розробника, який не є Java, Java схожа на величезну кількість шумових плит та шум лінії. Це не означає, що ви не можете зробити справжню роботу мовою.
Джеймс Мур

Ви можете використовувати reduceLeft (add) замість foldLeft (0) (add). Я думаю, це легше читати, коли вашим початковим елементом є нульовий / ідентичний елемент групи.
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

Шаблон вимикача схеми з випуску Майкла Ніярда у 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

Я готую документ, який містить кілька прикладів коду Java та Scala, використовуючи лише прості для розуміння особливості Scala:

Scala: Краща Java

Якщо ви хочете, щоб я до нього щось додавав, будь ласка, відповідайте у коментарях.


Назва "Scala: Краща Java" неправдива
полювання за качками

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: Чи нескінченний ітератор поганий дизайн?

Ще одним хорошим прикладом є функції першого класу та закриття:

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. Я вважаю це надзвичайно корисним для швидкого тестування фрагментів коду.


Зверніть увагу, що сито занадто повільне, щоб бути практичним.
Елазар Лейбович

@oxbow_lakes для цих прикладів немає еквівалентної Java.
dbyrne

@dbyme Неправда. Ви можете легко підкласирувати Java Iterableі Iteratorстворювати нескінченні потоки.
Даніель К. Собрал

@dbyrne "Ще одна річ, яку цей приклад показує, що java не може зробити, це запуск коду з інтерпретатора / REPL. Я вважаю це надзвичайно корисним для швидкого тестування фрагментів коду." Я використовую сторінку записів в Eclipse для випробування фрагментів Java. Роблячи більшість, якщо не всі Java працюють в цій IDE, мені не потрібен 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, і (це є можливою причиною, чому) він зараз для мене виглядає абсолютно нечитабельним.
Роман

Це розділення загального списку типу T, використовуючи надану функцію розділення як захист у застереженнях, що відповідають шаблону оператора case.
ПРОСТО МОЕ правильне ДУМКУ

3
Дивно. Я навіть не віддалено експерт Scala і можу це зрозуміти.
ДАЙТЕ МОЕ правильне ДУМКА
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.