大叔经验分享(17)编程实践对比Java vs Scala
scala
官方地址 https://www.scala-lang.org/
本文尽可能包含了一些主要的java和scala在编程实践时的显著差异,展现scala的代码的简洁优雅;scala通吃<面向对象编程Object Oriented Programming>和<函数式编程Functional Programming>,有很多开源组件都用scala开发(比如spark、kafka等),虽然java从8开始支持lambda表达式,有些方面已经接近scala,但是...
直接看代码对比:
一 Loop循环
1 for
取出0-10之间的偶数
scala
for (i <- 0 to 10 if i % 2 == 0) println(i) //or for (i <- 0 to 5) println(i * 2) //or for (i <- 0 until 6) println(i * 2)
//or
Array.range(0, 10, 2).foreach(println)
java
for (int i = 0; i <= 10; i++) { if (i % 2 == 0) { System.out.println(i); } } //or for (int i = 0; i <= 10; i += 2) { System.out.println(i); } //or for (int i = 0; i <= 5; i++) { System.out.println(i * 2); }
输出
0
2
4
6
8
10
2 foreach
迭代输出
scala
val list = List(2, 4, 1, 3, 5)
list.foreach(println)
java
List<Integer> list = Arrays.asList(new Integer[]{2, 4, 1, 3, 5}); for (Integer item : list) { System.out.println(item); } //or list.forEach((item) -> System.out.println(item));
输出
2
4
1
3
5
二 Functional函数式
函数式即将函数作为变量的一种,来看常见的包装应用
scala
def wrapper(str : String, f : ((String) => String)): Unit = { println("wrapper start") println(f(str)) println("wrapper end") } def say(str : String) : String = "hello " + str wrapper("test", say) //or wrapper("test", (str => "hello " + str))
java
interface SayInterface { public String say(String str); } public void wrapper1(String str, SayInterface si) { System.out.println("wrapper start"); System.out.println(si.say(str)); System.out.println("wrapper end"); } //or public void wrapper2(String str, Function<String, String> f) { System.out.println("wrapper start"); System.out.println(f.apply(str)); System.out.println("wrapper end"); } this.wrapper1("test", new SayInterface() { @Override public String say(String str) { return "hello " + str; } }); //or this.wrapper1("test", ((item) -> "hello " + item)); //or this.wrapper2("test", ((item) -> "hello " + item));
在早期的Java中函数式等价于命令模式,需要定义一个命令接口,然后可以传入不同的接口实现,这样又形成策略模式,比如jdk的排序接口;
输出
wrapper start
hello test
wrapper end
三 Array Collection
1 数组相加
scala
val arr1 = Array(1, 2) val arr2 = ArrayBuffer(1, 3) arr2 += (4) val arr3 = arr1 ++ arr2 println(arr3.mkString(","))
java
Integer[] arr1 = new Integer[]{1, 2}; Integer[] arr2 = new Integer[]{1, 3}; Integer[] arr3 = new Integer[arr1.length + arr2.length]; for (int i = 0; i < arr1.length; i++) { arr3[i] = arr1[i]; } for (int i = 0; i < arr2.length; i++) { arr3[arr1.length + i] = arr2[i]; } for (Integer item : arr3) { System.out.println(item); } //or List<Integer> list = new ArrayList<>(); list.addAll(Arrays.asList(arr2)); list.addAll(Arrays.asList(arr3)); list.add(4); list.forEach((item) -> System.out.println(item));
输出
1,2,1,3
2 创建Map及添加entry
scala
// val map1 = Map("a" -> 1, "b" -> 2, "c" -> 3) var map1 = Map("a" -> 1, "b" -> 2) map1 += ("c" -> 3) map1.foreach(println)
java
Map<String, Integer> map1 = new HashMap<>(); map1.put("a", 1); map1.put("b", 2); map1.put("c", 3); map1.forEach((key, value) -> System.out.println(key + ", " + value));
输出
(a,1)
(b,2)
(c,3)
3 合并两个Map
两个Map中key相同时将value相加
scala
val map1 = Map("a" -> 1, "b" -> 2) val map2 = Map("a" -> 1, "c" -> 3) Array.concat(map1.toArray, map2.toArray).groupBy(_._1).map(item => (item._1, item._2.map(_._2).reduce(_ + _))).foreach(println)
java
Map<String, Integer> map1 = new HashMap<>(); map1.put("a", 1); map1.put("b", 2); Map<String, Integer> map2 = new HashMap<>(); map2.put("a", 1); map2.put("c", 3); //merge map1 and map2 to mapMerge Map<String, Integer> mapMerge = new HashMap<>(); mapMerge.putAll(map1); for (String key : map2.keySet()) { if (mapMerge.containsKey(key)) { mapMerge.put(key, mapMerge.get(key) + map2.get(key)); } else { mapMerge.put(key, map2.get(key)); } } mapMerge.forEach((key, value) -> System.out.println(key + ", " + value));
输出
(b,2)
(a,2)
(c,3)
4 mkString
将集合元素逗号分隔输出
scala
val arr = Array(2, 4, 1, 3, 5)
println(arr.mkString(","))
java
public String mkStringInJava(Object[] arr, String seperator) { StringBuffer buf = new StringBuffer(); for (Object item : arr) { buf.append(seperator).append(item); } return buf.toString().substring(seperator.length()); } Integer[] arr = new Integer[]{2, 4, 1, 3, 5}; System.out.println(this.mkStringInJava(arr, ","));
输出
2,4,1,3,5
5 统计最小、最大、平均值
scala
val arr = Array(2, 4, 1, 3, 5)
println(arr.min + ", " + arr.max + ", " + arr.sum.toDouble / arr.length)
java
Integer[] arr = new Integer[]{2, 4, 1, 3, 5}; Integer min = null; Integer max = null; Integer sum = 0; for (Integer item : arr) { sum += item; if (min == null || min > item) { min = item; } if (max == null || max < item) { max = item; } } System.out.println(min + ", " + max + ", " + ((double)sum / arr.length));
输出
1, 5, 3.0
6 简单排序
正序、倒叙
scala
val arr = Array(2, 4, 1, 3, 5) //1 println(arr.sorted.mkString(",")) //2 println(arr.sorted.reverse.mkString(",")) //3 println(arr.sortWith((v1 : Int, v2 : Int) => v2 < v1).mkString(","))
java
Integer[] arr = new Integer[]{2, 4, 1, 3, 5}; //1 Arrays.sort(arr); for (Integer item : arr) { System.out.println(item); } //or Arrays.asList(arr).forEach((v) -> System.out.println(v)); //2 for (int i = arr.length - 1; i >= 0; i--) { System.out.println(arr[i]); } //3 Arrays.sort(arr, new Comparator<Integer>(){ @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }); //or Arrays.sort(arr, ((Integer v1, Integer v2) -> v2 - v1)); for (Integer item : arr) { System.out.println(item); }
输出
1,2,3,4,5
5,4,3,2,1
5,4,3,2,1
7 flatMap distinct
将数组中每个元素拆成多个元素并去重
scala
val arr = Array("1,2,3", "1,4,5")
arr.flatMap(_.split(",")).distinct.foreach(println)
java
String[] arr = new String[]{"1,2,3", "1,4,5"}; Set<String> set = new HashSet<>(); for (String item : arr) { set.addAll(Arrays.asList(item.split(","))); } set.forEach((item) -> System.out.println(item));
输出
1
2
3
4
5
8 foldLeft
将数组中值为奇数的元素求和
scala
val arr = Array(2, 4, 1, 3, 5) println(arr.foldLeft(0)((result, item) => result + (if (item % 2 != 0) item else 0)))
java
Integer[] arr = new Integer[]{2, 4, 1, 3, 5}; Integer sumOdd = 0; for (Integer item : arr) { if (item % 2 == 1) { sumOdd += item; } } System.out.println(sumOdd);
输出
9
9 filter map collect
将数组中小于3的元素提取一个新的集合,同时将新集合中的每个元素*3
scala
val arr = Array(2, 4, 1, 3, 5) arr.filter(_ < 3).map(_ * 3).foreach(println) //or arr.collect({case item : Int if item < 3 => item * 3}).foreach(println)
java
Integer[] arr = new Integer[]{2, 4, 1, 3, 5}; List<Integer> result = new ArrayList<>(); for (Integer item : arr) { if (item < 3) { result.add(item * 3); } } result.forEach((item) -> System.out.println(item));
输出
6
3
三 Tuple及Bean
1 定义bean class
scala
class Dummy(val name : String, val age : Int){ override def toString = name + "," + age }
java
class Dummy { public Dummy(String name, Integer age) { this.name = name; this.age = age; } @Override public String toString() { return this.name + "," + this.age; } private String name = null; private Integer age = null; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
熟悉的java bean class定义,field、getter、setter、constructor、toString等;
2 Bean复杂排序
scala
val arr1 = Array(new Dummy("a", 1), new Dummy("b", 3), new Dummy("a", 2), new Dummy("b", 1)) //1 println(arr1.sortBy(_.name).mkString("-")) //2 println(arr1.sortBy(_.age).mkString("-")) //3 println(arr1.sortWith((item1, item2) => if (item1.name.equals(item2.name)) item1.age < item2.age else item1.name.compareTo(item2.name) < 0).mkString("-"))
java
Dummy[] arr = new Dummy[]{new Dummy("a", 1), new Dummy("b", 3), new Dummy("a", 2), new Dummy("b", 1)}; //1 Arrays.sort(arr, new Comparator<Dummy>(){ @Override public int compare(Dummy d1, Dummy d2) { return d1.getName().compareTo(d2.getName()); } }); //or Arrays.sort(arr, ((Dummy d1, Dummy d2) -> d1.getName().compareTo(d2.getName()))); //or Arrays.sort(arr, Comparator.comparing(Dummy::getName)); System.out.println(this.mkStringInJava(arr, "-")); //2 Arrays.sort(arr, Comparator.comparing(Dummy::getAge)); System.out.println(this.mkStringInJava(arr, "-")); //3 Arrays.sort(arr, ((Dummy d1, Dummy d2) -> { Integer result = d1.getName().compareTo(d2.getName()); return result != 0 ? result : d1.getAge() - d2.getAge(); })); System.out.println(this.mkStringInJava(arr, "-"));
输出
a,1-a,2-b,3-b,1
a,1-b,1-a,2-b,3
a,1-a,2-b,1-b,3
3 Tuple
scala
def statistics(arr : Array[Int]) : (Int, Int, Double) = (arr.min, arr.max, arr.sum.toDouble / arr.length) val arr = Array(2, 4, 1, 3, 5) val s = statistics(arr) println(s._1 + ", " + s._2 + ", " + s._3)
java
class Statistics { private Integer min = null; private Integer max = null; private Double avg = null; public Integer getMin() { return min; } public void setMin(Integer min) { this.min = min; } public Integer getMax() { return max; } public void setMax(Integer max) { this.max = max; } public Double getAvg() { return avg; } public void setAvg(Double avg) { this.avg = avg; } } public Statistics statistics(Integer[] arr) { Statistics result = new Statistics(); Integer min = null; Integer max = null; Integer sum = 0; for (Integer item : arr) { sum += item; if (min == null || min > item) { min = item; } if (max == null || max < item) { max = item; } } result.setMin(min); result.setMax(max); result.setAvg((double)sum / arr.length); return result; } Integer[] arr = new Integer[]{2, 4, 1, 3, 5}; Statistics s = statistics(arr); System.out.println(s.getMin() + ", " + s.getMax() + ", " + s.getAvg());
java中方法返回多个值时通常需要借助class来实现(将多个值作为class的属性);
输出
1, 5, 3.0
4 Tuple排序
scala
val arr = Array(("a", 1), ("b", 3), ("a", 2), ("b", 1)) println(arr.sortBy(_._1).mkString("-")) println(arr.sortBy(_._2).mkString("-")) println(arr.sortWith((item1, item2) => if (item1._1.equals(item2._1)) item1._2 < item2._2 else item1._1.compareTo(item2._1) < 0).mkString("-"))
java中需要借助第三方库才能支持数量有限的Tuple,这里不演示了;
输出
(a,1)-(a,2)-(b,3)-(b,1)
(a,1)-(b,1)-(a,2)-(b,3)
(a,1)-(a,2)-(b,1)-(b,3)
四 IO
1 read读文件
scala
Source.fromFile("test.log").getLines().foreach(println)
java
BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(new File("test.log"))); String line = null; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } }
2 write写文件
scala
var writer : PrintWriter = null try { writer = new PrintWriter("test.log") writer.write("test") writer.flush() } catch {case e : Exception => e.printStackTrace} finally {try {if (writer != null) writer.close()} catch {case e : Exception => e.printStackTrace}}
java
BufferedWriter writer = null; try { writer = new BufferedWriter(new FileWriter(new File("test.log"))); writer.write("test"); writer.flush(); } catch (IOException e) { e.printStackTrace(); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } }
五 Actor 定时
akka.actor
1 Actor
scala
import akka.actor.{Actor, ActorSystem, Props} import akka.util.Timeout class TestActor extends Actor { def receive = { case arg => { val result = "hello : " + arg println(result) Thread.sleep(3000) result } } } val system = ActorSystem("ActorSystem") val actor = system.actorOf(Props(new TestActor), "TestActor") actor ! "world async" implicit val timeout = Timeout(5, TimeUnit.SECONDS) import akka.pattern._ val feature = actor ? "world async with feature" feature.foreach(result => println(result))
java
java.util.concurrent.LinkedBlockingQueue
java.util.concurrent.ThreadPoolExecutor
java.util.concurrent.Callable
java.util.concurrent.Future
实现效果:异步非阻塞,object接收消息放到queue中,同时内置ThreadPool不断处理消息;
2 定时
scala
val system = ActorSystem("ActorSystem") import system.dispatcher system.scheduler.schedule(Duration.create(1000, TimeUnit. MILLISECONDS), Duration.create(1000, TimeUnit. MILLISECONDS))( println("hello") )
java
java.util.Timer
java.util.TimerTask
实现效果:定时执行task;
六 continue/break
scala
import scala.util.control.Breaks._ breakable { ... break ... }
java 原生支持
---------------------------------------------------------------- 结束啦,我是大魔王先生的分割线 :) ----------------------------------------------------------------
- 由于大魔王先生能力有限,文中可能存在错误,欢迎指正、补充!
- 感谢您的阅读,如果文章对您有用,那么请为大魔王先生轻轻点个赞,ありがとう