Зразки коду 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.