Примеры кода Scala и Java, в которых код Scala выглядит проще / имеет меньше строк?

95

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

Если есть только образец Scala с комментарием типа «это абстрактная фабрика в Scala, в Java она будет выглядеть намного громоздче», то это также приемлемо.

Благодарность!

Мне больше всего нравится принятое и это ответы

Римский
источник
3
Немного поработав, вы можете найти множество образцов на rosettacode.org
nicerobot
4
Как может быть один правильный ответ на такой вопрос?
polygenelubricants
@polygenelubricants: а что вы предлагаете?
Роман
10
@Roman: Мы ожидаем, что Scala будет более лаконичной. Было бы интереснее, если бы вы могли найти что-то, что было бы более лаконично выражено в Java, чем в Scala.
Randall Schulz
1
@Randall Schulz: все знают, что Scala более лаконична, но иногда в академических целях нам нужно доказательство с примерами и базовой теорией.
Роман

Ответы:

77

Давайте улучшим пример стека и воспользуемся case-классами Scala :

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

Вышеупомянутый класс Scala содержит все функции указанного ниже класса Java и некоторые другие - например, он поддерживает сопоставление с образцом (чего нет в Java). Scala 2.8 добавляет именованные аргументы и аргументы по умолчанию, которые используются для создания метода копирования для классов case, что дает те же возможности, что и методы with * следующего класса 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, не в конструкторе, поле, или аксессора: gist.github.com/424375
ретроним
2
Поощряет всякие плохие методы получения / установки. Сеттеры следует добавлять только с крайней неохотой, геттеры следует добавлять только в случае необходимости. Хороший пример того, как добавление «Простоты» приводит к вредным привычкам.
Bill K
7
@Bill K: Хорошо, тогда у нас будет case class Person(val firstName: String, val lastName: String) Ну и что? Сделать эту вещь приватной тоже можно, но это не имеет никакого смысла из-за неприменения и т. Д.
soc
1
@shiva case class Person(private val firstName: String), но тогда вам не следует использовать case-классы. Вместо этого do class Person(firstName: String)и firstNameпо умолчанию закрыто.
nilskp
1
@shiva Нет. Разница между valи private valзаключается в том, являются ли методы доступа, т. е. firstName()и firstName(String), общедоступными или частными. В Scala поля всегда приватны. Чтобы Scala могла генерировать методы get / set в стиле Java (в дополнение к средствам доступа в стиле Scala), существует @BeanPropertyаннотация.
Эско Луонтола
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 не будет генерировать getFirstNameи getLastNameметоды. Для этого вам необходимо аннотировать параметры scala.reflect.BeanPropertyаннотациями.
Abhinav Sarkar
7
@ abhin4v: Да, но соглашение о коде в Scala не должно иметь префиксов доступа с get. Идиоматический код Java отличается от идиоматического кода Scala. Иногда isпрефикс используется для логических значений. davetron5000.github.com/scala-style/naming_conventions/methods/…
Эско Луонтола 01
7
Вы можете сделать это case classи получить toString, equalsпричем hashCodeбесплатно (и вам также не нужно valявно приводить аргументы ):case class Person(firstName: String, lastName: String)
Джеспер
@shiva, для case class, а не для просто class.
nilskp
23

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

Пояснение:

  • Вход: Список <String>
  • Вывод: Карта <Персонаж, Список <String>>
  • Клавиша карты - от «А» до «Я».
  • Каждый список на карте отсортирован.

Ява:

import java.util.*;

class Main {
  public static void main(String[] args) {
    List<String> keywords = Arrays.asList("Apple", "Ananas", "Mango", "Banana", "Beer"); 
    Map<Character, List<String>> result = new HashMap<Character, List<String>>(); 
    for(String k : keywords) {   
      char firstChar = k.charAt(0);     
      if(!result.containsKey(firstChar)) {     
        result.put(firstChar, new  ArrayList<String>());   
      }     
      result.get(firstChar).add(k); 
    } 
    for(List<String> list : result.values()) {   
      Collections.sort(list); 
    }
    System.out.println(result);         
  }
}

Скала:

object Main extends App {
  val keywords = List("Apple", "Ananas", "Mango", "Banana", "Beer")
  val result = keywords.sorted.groupBy(_.head)
  println(result)
}
пропавший
источник
Вы можете использовать v.sorted вместо (v sortBy identity).
Eastsun 02
1
А в Scala 2.8 вы можете использовать mapValues ​​(_.sorted) вместо map {case ...}
Алекс
10
В Java 8 код почти идентичен Scalas: ключевые слова.stream (). Sorted (). Collect (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());
  }
});

Скала:

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метод принимает функцию , 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 09
@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();
    }
  }
}



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

[РЕДАКТИРОВАТЬ Билл; Проверить комментарии для обсуждения] -

Хм, как это сделать, не отвечая в неформатированном разделе ответов ... Хм. Думаю, я отредактирую ваш ответ и позволю вам удалить его, если он вас беспокоит.

Вот как я бы сделал это на 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 действительно хорош
oluies
5
Код Java написан именно для анализа этого конкретного XML-файла без попыток повторного использования и большого количества дублированного кода. Кто бы это ни написал, либо пытался сознательно выглядеть так, как будто он не понимает кодирования, либо не понимает кодирования.
Bill K
@Bill K: Я никогда не занимался синтаксическим анализом XML на Java, поэтому я взял этот пример с какого-то случайного сайта. Не стесняйтесь редактировать Java-часть ответа, я не против.
missingfaktor
Что ж, давайте предположим, что вы говорите о языковых различиях, а не о различиях в библиотеках - в этом случае они будут почти идентичными. Единственная языковая разница во втором примере - это совпадение / регистр, которое может быть выполнено в одной строке как цикл for, если это реализовано библиотекой таким образом.
Bill K
@Bill K: Нет, вы совершенно не правы. Здесь работают две очень мощные функции Scala: 1. XML-литералы 2. Сопоставление с образцом. В Java нет ни того, ни другого. Таким образом, эквивалентный код Java, написанный в какой-то гипотетической библиотеке, точно НЕ будет идентичным. (Попробуйте написать, и вы узнаете.)
missingfaktor 06
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");

Скала:

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 03
@huynhjl, у меня плохо. Откатил обратно.
missingfaktor 03
3
Можно еще короче:val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
Джефф Риди
2
Еще короче: val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }а потомtodos("hi")()
Мартин Ринг
8

Мне понравился этот простой пример сортировки и преобразования, взятый из книги Дэвида Поллака Beginning Scala:

В Scala:

def validByAge(in: List[Person]) = in.filter(_.valid).sortBy(_.age).map(_.first)
case class Person(val first: String, val last: String, val age: Int) {def valid: Boolean = age > 18}
validByAge(List(Person("John", "Valid", 32), Person("John", "Invalid", 17), Person("OtherJohn", "Valid", 19)))

В Java:

public static List<String> validByAge(List<Person> in) {
   List<Person> people = new ArrayList<Person>();
   for (Person p: in) {
     if (p.valid()) people.add(p);
   }
   Collections.sort(people, new Comparator<Person>() {
      public int compare(Person a, Person b) {
        return a.age() - b.age();
      } 
   } );
   List<String> ret = new ArrayList<String>();
     for (Person p: people) {
       ret.add(p.first);
     }
   return ret;
}

public class Person {
    private final String firstName;
    private final String lastName;
    private final Integer age;
    public Person(String firstName, String lastName, Integer age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    public String getFirst() {
        return firstName;
    }
    public String getLast() {
        return lastName;
    }
    public Integer getAge() {
       return age;
    }
    public Boolean valid() {
       return age > 18;
    }
}

List<Person> input = new ArrayList<Person>();
input.add(new Person("John", "Valid", 32));
input.add(new Person("John", "InValid", 17));
input.add(new Person("OtherJohn", "Valid", 19));

List<Person> output = validByAge(input)
Арьян Блокзейл
источник
8

Я сейчас пишу игру в блэкджек на Scala. Вот как будет выглядеть мой метод дилераWins на 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));
}
MikeFHay
источник
У scala очень сложный синтаксис. нужно так много запомнить :-(
AZ_ 07
Scala похожа на CSS, многие атрибуты и свойства нужно запоминать
AZ_ 07
1
лучше:def dealerWins = !(players exists (_ beats dealer))
Кевин Райт
6

Как насчет быстрой сортировки?


Ява

Ниже приведен пример Java, найденный с помощью поиска в Google.

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) или нет? Обычно для связанных списков используется сортировка слиянием или подобное.
Эско Луонтола 02
3
Он также не является хвостовым рекурсивным и, следовательно, непригоден в качестве высокопроизводительного алгоритма (или алгоритма, который не переполняет стек)
oxbow_lakes
Спасибо за полезные комментарии. Я где-то видел подобную быструю сортировку и был впечатлен ее компактностью, очевидно, я не придал ей особого значения. Я увлекся сравнением LOC, которое всегда соблазняет Scala v Java.
Don Mackenzie
2
Быстрая сортировка не является O (n ^ 2) в функциональных списках, но определенно таит в себе опасность. Асимптотически это по-прежнему среднее значение O (n log n) , но существует более высокая статистическая вероятность достижения наихудшего случая O (n ^ 2), потому что мы всегда выбираем точку поворота в начале списка, а не выбираем ее случайным образом .
Daniel Spiewak 03
Двойная фильтрация - это плохо. Посмотрите в моем ответе на ваш вопрос, как этого partitionизбежать.
Дэниел С. Собрал,
6

Мне настолько понравился ответ пользователя 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 unknown
@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, а здесь в 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)
    } 
неизвестный пользователь
источник
Мне очень нравится этот пример. Он избегает простого способа сравнения классов case и не делает ошибку, показывая код 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;
    }

В 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:


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 неясен и сложен ...
Джеспер
Я немного переформатировал, чтобы улучшить пример. Надеюсь, что это не повредит Scala.
Thomas
5
scala> от 1 до 10 map (x => x * x) sum res0: Int = 385 Давайте посмотрим, как разработчик Java вызывает этот загадочный запрос. В этот момент пальцы в ушах говорят «нах-на-нах».
psp
3
@Jesper Для разработчика, не связанного с Java, Java выглядит как огромное количество шаблонов и линейного шума. Это не значит, что вы не можете выполнять настоящую работу на языке.
Джеймс Мур
Вы можете использовать reduceLeft (добавить) вместо foldLeft (0) (добавить). Я думаю, что легче читать, когда ваш начальный элемент является нулевым элементом / элементом идентичности группы.
Debilski 02
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

Паттерн "Автоматический выключатель" из альбома Майкла Найгарда "Release It in 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 для "Автоматический выключатель" + ваш язык.

oluies
источник
3

Я готовлю документ, который дает несколько примеров кода Java и Scala, используя только простые для понимания функции Scala:

Scala: лучшая Java

Если вы хотите, чтобы я что-то добавил, ответьте в комментариях.

HRJ
источник
Название «Scala: A better Java» вводит в заблуждение
duckhunt
2

Бесконечные потоки с ленивой оценкой - хороший пример:

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. Я считаю это чрезвычайно полезным для быстрого тестирования фрагментов кода.

Dbyrne
источник
Обратите внимание, что сито слишком медленное, чтобы быть практичным.
Элазар Лейбович
@oxbow_lakes для этих примеров нет эквивалентной java.
dbyrne 03
@dbyme Неправда. Вы можете легко создать подклассы Java Iterableи Iteratorсоздавать бесконечные потоки.
Дэниел С. Собрал,
@dbyrne "Еще одна вещь, которую этот пример показывает, что java не может сделать, - это запускать код из интерпретатора / REPL. Я нахожу это чрезвычайно полезным для быстрого тестирования фрагментов кода." Я использую страницу альбома в Eclipse, чтобы опробовать фрагменты Java. Я выполняю большую часть, если не всю работу Java в этой среде IDE, поэтому мне не нужен REPL. Я использовал notepad.exe и javac в первые дни, когда я не был уверен в функциях языка или библиотеки, и через короткое время все прошло очень хорошо и быстро - хотя REPL несколько проще в использовании - и быстрее. Я мог бы вообще избежать взлома блокнота, установив VisualAge, который у нас уже был
2

Почему никто не публиковал это раньше:

Ява:

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

116 знаков.

Скала:

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

56 символов.

OscarRyz
источник
1
Applicationхарактеристика считается вредной ... scala-blogs.org/2008/07/…
missingfaktor 03
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 и могу в этом разобраться.
ТОЛЬКО МОЕ ПРАВИЛЬНОЕ МНЕНИЕ