我需要一些Scala和Java代码的代码示例(并且我也对此感到很好奇),这些示例表明Scala代码比用Java编写的代码更简单,简洁(当然,两个示例都应该解决相同的问题)。
如果只有带有注释的Scala示例,例如“这是Scala中的抽象工厂,在Java中看起来会很麻烦”,那么这也是可以接受的。
谢谢!
我最喜欢的所有接受和这个答案
我需要一些Scala和Java代码的代码示例(并且我也对此感到很好奇),这些示例表明Scala代码比用Java编写的代码更简单,简洁(当然,两个示例都应该解决相同的问题)。
如果只有带有注释的Scala示例,例如“这是Scala中的抽象工厂,在Java中看起来会很麻烦”,那么这也是可以接受的。
谢谢!
我最喜欢的所有接受和这个答案
Answers:
case class Person(firstName: String, lastName: String)
上面的Scala类包含下面的Java类的所有功能,以及更多其他功能 -例如,它支持模式匹配(Java没有此功能)。Scala 2.8添加了命名参数和默认参数,这些参数用于为案例类生成一个复制方法,它具有与以下Java类的with *方法相同的功能。
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)
case class Person(val firstName: String, val lastName: String)
什么呢?使那件事私人将是可能的也是如此,但并没有任何意义,因为不应用等
case class Person(private val firstName: String)
,但是您不应该使用案例类。相反,这样做class Person(firstName: String)
并firstName
默认为私有。
val
和之间的区别private val
是访问器方法(即firstName()
和firstName(String)
)是公共的还是私有的。在Scala中,字段始终是私有的。为了使Scala生成Java风格的get / set方法(除了Scala风格的访问器),还有@BeanProperty
注释。
我发现这令人印象深刻
爪哇
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
批注。
get
。惯用的Java代码与惯用的Scala代码不同。有时,is
前缀用于布尔值。davetron5000.github.com/scala-style/naming_conventions/methods/...
case class
,并得到toString
,equals
并hashCode
免费(你也不必使论点val
明确):case class Person(firstName: String, lastName: String)
case class
,不只是class
。
任务:编写一个程序以索引关键字列表(如书籍)。
说明:
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)
}
任务:
您有一个包含字段和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))
自从我写了这个答案以来,已经取得了很大的进步。lambda(和方法引用)终于进入了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
。
Lambda和方法引用只是函数式编程的冰山一角。:)
任务:
您已经有了一个如下所示的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
字段。
爪哇: [从这里获得 ]
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通常在某些方面对库的支持很差,但是请继续-将Java十年(?)的旧XML库的可怕用法与基于简洁的实现进行比较是不公平的,而且还很遥远。比较语言!
根据字符串执行的动作映射。
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();
todos.get("hi")
返回Option[()=>Unit]
正确匹配所需的值。
val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }
然后todos("hi")()
我现在正在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));
}
def dealerWins = !(players exists (_ beats dealer))
我喜欢这个简单的排序和转换示例,摘自David Pollak的“ 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)
Quicksort怎么样?
以下是通过Google搜索找到的Java示例,
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))
}
}
partition
,以免发生这种情况。
我非常喜欢未知用户的 回答,因此我将尝试对其进行改进。下面的代码不是 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)
}
我非常喜欢在mutableMap中找到的getOrElseUpdate方法,这里显示的是第一个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)
}
这是一个非常简单的示例:平方整数,然后将它们相加
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转换为Map:
<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晦涩而复杂…………
问题:您需要设计一种将异步执行任何给定代码的方法。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
}
来自Michael Nygard在FaKods中的Release It的Circuit Breaker模式 (链接到代码)
在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参考“断路器” +您的语言。
为什么以前没有人发布此内容:
Java:
class Hello {
public static void main( String [] args ) {
System.out.println("Hello world");
}
}
116个字符。
Scala:
object Hello extends App {
println("Hello world")
}
56个字符。
Application
认为有害的特质... scala-blogs.org/2008/07/…– missingfaktor 2010
惰性计算的无限流是一个很好的例子:
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运行代码。我发现这对于快速测试代码段非常有用。
Iterable
并Iterator
生成无限流。
此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中将是完全不可读的。