Образцы кода Scala и Java, где код Scala выглядит проще / имеет меньше строк? - PullRequest
91 голосов
/ 01 июня 2010

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

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

Спасибо!

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

Ответы [ 18 ]

75 голосов
/ 02 июня 2010

Давайте улучшим пример укладчика и используем классы дел 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)
45 голосов
/ 01 июня 2010

Я нашел это впечатляющим

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

Scala

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

Как и эти (извините, что не вставил, я не хотел украсть код)

23 голосов
/ 02 июня 2010

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

Пояснение:

  • Ввод: список
  • Вывод: Карта <Символ, Список <String>>
  • Ключ карты от 'A' до 'Z'
  • Каждый список на карте отсортирован.

Java

import java.util.*;

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

Scala:

object Main extends App {
  val keywords = List("Apple", "Ananas", "Mango", "Banana", "Beer")
  val result = keywords.sorted.groupBy(_.head)
  println(result)
}
11 голосов
/ 21 октября 2010

Задача:

У вас есть список 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, и они штурмом захватывают мир 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.

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

10 голосов
/ 04 июня 2010

Задача:

У вас есть 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 с реализацией, основанной на краткости, просто не справедливо - и далек от сравнения языков!

9 голосов
/ 03 июня 2010

Карта действий, выполняемых в зависимости от строки.

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();
7 голосов
/ 24 февраля 2012

Я сейчас пишу игру в блэкджек в 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));
}
7 голосов
/ 02 июня 2010

Мне понравился этот простой пример сортировки и преобразования, взятый из книги Дэвида Поллака «Начальная Скала»:

В 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 голосов
/ 06 июня 2010

Мне очень нравится метод 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;
}

yes - 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)
    } 
6 голосов
/ 02 июня 2010

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


Java

Ниже приведен пример 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. Открытый сезон для улучшителей кода; @)

def qsort(l: List[Int]): List[Int] = {
  l match {
    case Nil         => Nil
    case pivot::tail => qsort(tail.filter(_ < pivot)) ::: pivot :: qsort(tail.filter(_ >= pivot))
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...