Выборки Scala и Java кодируют, где код Scala выглядит более простым / меньше строк?

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

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

Спасибо!

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

92
задан Community 23 May 2017 в 12:17
поделиться

15 ответов

Давайте улучшим пример укладчика и воспользуемся классами кейсов 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)
75
ответ дан 24 November 2019 в 06:26
поделиться

Почему никто не разместил это раньше:

Java:

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

116 символов.

Scala:

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

56 символов.

2
ответ дан 24 November 2019 в 06:26
поделиться

Хорошим примером являются бесконечные потоки с отложенным вычислением:

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

Другой хороший пример - функции первого класса и замыкания:

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

1
ответ дан 24 November 2019 в 06:26
поделиться

Проблема: необходимо разработать метод, который будет выполнять любой заданный код асинхронно.

Решение на 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 (используя actors):

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    
}
5
ответ дан 24 November 2019 в 06:26
поделиться

Это очень простой пример: возвести целые числа в квадрат, а затем сложить их


    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 )

Этот 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)
5
ответ дан 24 November 2019 в 06:26
поделиться

Мне понравился этот простой пример сортировки и преобразования, взятый из книги Дэвида Поллака "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)
7
ответ дан 24 November 2019 в 06:26
поделиться

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

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)

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

45
ответ дан 24 November 2019 в 06:26
поделиться

Как насчет Quicksort?


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

Быстрая попытка сделать версию на 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))
  }
}
6
ответ дан 24 November 2019 в 06:26
поделиться

Этот код 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, если это вообще возможно.

0
ответ дан 24 November 2019 в 06:26
поделиться

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

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();
10
ответ дан 24 November 2019 в 06:26
поделиться

Задача:

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

10
ответ дан 24 November 2019 в 06:26
поделиться

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

Объяснение:

  • Вход: Список
  • Выход: Сопоставление <Символ, Список >
  • Ключ сопоставления - от «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)
}
23
ответ дан 24 November 2019 в 06:26
поделиться

Схема автоматического выключателя из «Release It» Майкла Найгарда в 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
ответ дан 24 November 2019 в 06:26
поделиться

Мне очень нравится метод 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)
    } 
6
ответ дан 24 November 2019 в 06:26
поделиться

Мне настолько понравился ответ user unknown , я постараюсь его улучшить. Приведенный ниже код не является прямым переводом примера Java, но он выполняет ту же задачу с тем же API.

def wordCount (sc: Scanner, delimiter: String) = {
  val it = new Iterator[String] {
    def next = sc.nextLine()
    def hasNext = sc.hasNextLine()
  }
  val words = it flatMap (_ split delimiter iterator)
  words.toTraversable groupBy identity mapValues (_.size)
}
6
ответ дан 24 November 2019 в 06:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: