搜尋
首頁类库下载java类库Java/Scala互通實務 1:基礎操作

Java Bean

Java Bean有個特點,就是對於可修改屬性都會有對應的getter和setter方法(final屬性將只有getter方法)。由Java定義的物件在Scala中可以直接使用,並無二樣。而在Scala中定義Java Bean卻有些不同。

其實在Scala中可以像Java一樣來定義Java Bean:

// Scala中默认为public访问权限,包括属性和方法class Person {
  // 下划线在这里是一个占位符,它代码相应属性对应类型的默认值
  private var id: Int = _ 
  private var name: String = _;  def getId: Int = id;  def setId(id: Int) {    this.id = id
  }  def getName: String = name;  def setName(name: String) {    this.name = name;
  }
}

這樣寫的話,除了語法上與Java有些差別,其實定義的方式是一樣的。但其實Scala提供了註解來自動產生getter和setter函數:

import scala.beans.BeanPropertyclass Person {  @BeanProperty
  var id: Int = _  @BeanProperty
  var name: String = _  @BeanProperty
  val createdAt: LocalDateTime = _
}

除了使用傳統的class,在Scala中還可以使用case class來定義POJO:

case class SignRequest(@BeanProperty
                       account: String = null,                       @BeanProperty
                       password: String = null,                       @BeanProperty
                       captcha: String = null,                       @BeanProperty
                       var smsCode: String = null)

case class的主建構子聲明的參數將同時做為SignRequest的履性,且是val的(類似Java的public final)。在這裡,account、password和captcha將只產生getter函數。而smsCode將產生getter和setter函數,因為它使用var來修飾。

這裡有一個Java裡沒有的特 性:參數預設值,像C++、Python、ES6+ 一樣,Scala的參數是可以設定預設值的。因為Java Bean規格要求類別必需有參數為空的預設建構函數,而當case class的主建構子所有參數都設定預設值後,實例化這個類別時將相當於擁有一個空的預設建構子。

在Java中呼叫case class可見:com/hualongdata/springstarter/data/repository/UserRepositoryImpl.java。

基於註解的依賴注入

在Spring開發中,依賴注入是很常用的一個特性 。基於屬性的註解注入在Java和Scala中都是一樣的。但基於建構函式的依賴注入在Scala中有些特別,程式碼如下:

class SignController @Autowired()(userService: UserService,
                                  webUtils: WebUtils,
                                  hlTokenComponent: HlTokenComponent) {
  ......
}

在Scala中,單註解作用於建構函式上時需要類似方法呼叫的形式:@Autowired()。又因為Scala中,主建構函數必需定義在類別名稱之後的小括號內,所以註解需要緊跟在類別名稱之號,主建構子左括號之前。

在Scala中使用主建構函式的注入元件是一個更好的實踐,它同時擁有註入的 元件為private final存取權。相同效果的Java程式碼需要更多:

public SignController {
    private final UserService userService;
    private final WebUtils webUtils;
    private final HlTokenComponent hlTokenComponent;

    public SignController(UserService userService, WebUtils webUtils, HlTokenComponent hlTokenComponent) {
        this.userService = userService;
        this.webUtils = webUtils;
        this.hlTokenComponent = hlTokenComponent;
    }
}

可以看到,Scala的版本程式碼量更少,同時看起來更簡潔。

註解參數

數組參數

@RestController
@RequestMapping(Array("/sign"))
class SignController @Autowired()(userService: UserService,
  ......

在Scala中,對於註解的數組參數當只設定一個元素時是不能像Java一樣賤一個字串的,必需顯示的定義一個數組。

參數值必需為常數

在Scala中,當為註解的某個參數賤值時必需使用常數,像:@RequestMapping(Array(Constants.API_BASE + "/sign"))這樣的形式都是非法的。只能像這樣賤值:@RequestMapping(Array("/aip/sign"))

變長參數

在Scala中變長參數透過星號(*)來定義,程式碼如下:

def log(format: String, value: String*)

但是這樣定義出來的變參在Java中是不能存取的,因為Scala預設實作中value的型別為: Seq[Any],而Java中的變參型別其實是一個陣列( String[])。要解決這個問題非常簡單,在函式定義前加上scala.annotation.varargs註解就可以強制Scala使用Java的實作來實作變長參數。

集合庫

Scala有自己的一套集合库实现: scala.collection,分为不可变集合scala.collection.immutable和可变集合scala.collection.mutable。两者都实现了很多高阶函数,可以简化日常编程,同时Scala中推荐使用不可变集合。

Java集合到Scala集合

Scala提供了scala.collection.JavaConverters来转换Java集合到Scala集合:

import scala.collection.JavaConverters._  /**
    * 根据sheet名获取sheet所有单元格
    *
    * @param workbook  Excel [[Workbook]]对象
    * @param sheetName sheet 名
    * @return 返回所有有效单元格可迭代二维列表
    */
  def getSheetCells(workbook: Workbook, sheetName: String): Iterable[Iterable[RichCell]] = {
      workbook.getSheet(sheetName)
        .asScala
        .map(row => row.asScala.map(cell => new RichCell(cell)))
  }

workbook.getSheet方法返回的Sheet类型是实现了java.lang.Iterable接口的可迭代类型。为了使用Scala集合上提供的map高阶函数,我们需要把Java集合转换成Scala集合。可以通过在Java集合上调用.asScala函数来将其转换成Scala集合,这里运用了Scala里的隐式转换特性来实现。

Scala集合到Java集合

接下来我们看另外一个函数:

  @varargs
  def getSheets(workbook: Workbook, sheetNames: String*): java.util.List[Sheet] = {
    sheets(workbook, sheetNames: _ *).asJava
  }

这个函数实现的功能是根据传入的一个或多个Sheet名字从Excel里获取Sheet列表。sheets函数返回的是一个Scala集合:Seq[Sheet],通过getSheets代理函数将其转换成Java集合,通过在Seq[Sheet]上调用.asJava方法来实现自动转换。同样的,这里也运用了Scala的隐式转换特性。

Java代码中做集合转换

之前的例子都是在Scala代码中实现的,通过隐式转换这一特性我们发现做Java/Scala集合的相互转换是非常方便的。但在Java代码中做两者的转换就不那么直观了,因为Java没有隐式转换这一特性,我们需要显示的调用代码来先生成包装类,再调用.asScala或.asJava方法来转换集合类型:

import scala.collection.JavaConverters$;import scala.collection.mutable.Buffer;    public static void demo() {
        List<String> list = Arrays.asList("dd", "dd");        // Java List 到 Scala Buffer
        Buffer<String> scalaBuffer = JavaConverters$.MODULE$.asScalaBufferConverter(list).asScala();        // Scala Buffer 到 Java List
        List<String> javaList = JavaConverters$.MODULE$.bufferAsJavaListConverter(scalaBuffer).asJava();
    }

为Java和Scala同时提供API

当在项目中混用Java和Scala语言时,有个问题不得不重视。提供的API是用Java还是Scala来实现?实现的API是优先考虑兼容Java还是Scala?

对于API的实现,用Java或Scala均可。若使用Java实现,在Scala中调用是基本无压力的。而使用Scala实现时,为了兼容Java你可能不得不作一些折中。一个常用的方式是:使用Scala或Java来实现API,而再用Java或Scala来实现一个封装层(代理)作兼容。比如:Spark、Akka……,它们使用Scala来实现API,但提供了包装的Java API层。

一个好的实践是把Scala API放到scalaapi包路径(或者反之把Java API放到javaapi包路径)。

若我们只提供一个API,那就要尽量同时支持Java和Scala方便的 调用。比如使用@varargs注解来修饰变长参数。

对于参数需要集合类型,或返回值为集合类型的函数。我们除了使用上一节提供的JavaConverters来做自动/手动转换以外,也可以通过装饰器形式来提供Java或Scala专有的API。这里,我推荐Scala API函数名直接使用代表操作的名词/动词实现,而Java API在之前加上:get、set、create等前缀进行修饰。

def sheets(workbook: Workbook, sheetNames: String*): Seq[Sheet] = {
    sheetNames.map(sheetName => workbook.getSheet(sheetName))
  }  @varargs
  def getSheets(workbook: Workbook, sheetNames: String*): java.util.List[Sheet] = {
    sheets(workbook, sheetNames: _ *).asJava
  }

这里sheets和getSheets实现相同的功能,区别是第一个是Scala API,第二个是Java API。

结语

本文较详细的介绍了Java/Scala的互操作性,以上示例都来自作者及团队的实际工作。

这篇文章简单介绍了一些基础的Java/Scala互操作方法,接下来的文章将介绍些高级的互操作:Future、Optional/Option、lamdba函数、类与接口等。


陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱工具

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能