Java 8在Spring 4中的使用

Java 8在Spring 4中的使用

Spring4已经发布一段时间了,但是在国内大部分企业还一直沉浸在Spring 3.x的时代。今天无意在Infoq看到一片关于Spring 4中对Java 8性功能的使用,趁机看看Spring 4的功能以及Java 8 的一些新特性。

这篇文章大部分内容是翻译自:http://www.infoq.com/articles/spring-4-java-8

Spring 4对Lambda表达式的应用

在JDK中存在很多回调接口,老外叫做方法接口。比如RunnableComparable,Listener类的接口等等,这种接口我们一般习惯通过匿名类的方式实现它,它们的特点包括:接口定义简单(一般就一两个方法),我们只需要new出它们,但是从来不是我们调用它们,一般用于通知类型的场景。在Spring中类似这些接口也有很多,这里只列举出JDBC相关的接口:


public interface ConnectionCallback<T> {
    T doInConnection(Connection con) throws SQLException, DataAccessException;
}

public interface RowMapper<T>
{
    T mapRow(ResultSet rs, int rowNum) throws SQLException;
 }

JdbcTemplate下存在下面方法:


public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException

在Java 8之前我们是如下方式调用的:


jdbcTemplate.query("SELECT * from products", new RowMapper<Product>(){
@Override
public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
Integer id = rs.getInt("id");
String description = rs.getString("description");
Integer quantity = rs.getInt("quantity");
BigDecimal price = rs.getBigDecimal("price");
Date availability = rs.getDate("available_date");

Product product = new Product();
product.setId(id);
product.setDescription(description);
product.setQuantity(quantity);
product.setPrice(price);
product.setAvailability(availability);
return product;
}
});

但是在Java 8下面,我们可以通过Lambda表达式的方式:


jdbcTemplate.query("SELECT * from queries.products", (rs, rowNum) -> {
Integer id = rs.getInt("id");
String description = rs.getString("description");
Integer quantity = rs.getInt("quantity");
BigDecimal price = rs.getBigDecimal("price");
Date availability = rs.getDate("available_date");

Product product = new Product();
product.setId(id);
product.setDescription(description);
product.setQuantity(quantity);
product.setPrice(price);
product.setAvailability(availability);

return product;
});

这里我们并没有实例化一个RowMapper类,而是通过Lambda的方式来执行,相对之前简单明了。当然这需要Java 8的支持。依次类推,在Java 8下可以执行下面代码:


new Thread(()->{
    //do run method     
});

关于Lambda可以参照相关的资料,由于这里不是介绍Lambda的,而且我也不熟悉,所以就不误导大家了!

Spring 4和Java 8最新时间日期API

在Java 8之前,我们对日期的操作用的比较多的就是两个类(Date,SimpleDateFormate),用于时间转换和表示时间对象。在Java 8中提供了更加丰富的时间API,在java.time包下面有很多新的类来操作时间日期相关的类,比如:LocalDate,LocalTime以及LocalDateTime。Spring 4对这些新的API进行了兼容。例如下面的代码:


@RestController
public class ExampleController {

@RequestMapping("/date/{localDate}")
public String get(@DateTimeFormat(iso = ISO.DATE)LocalDate localDate)
{
    return localDate.toString();
}
}

如果localDate参数值是2015-02-13那么将会自动转换成LocalDate类的实体。

但是这只是Spring 4对它进行了支持,但是在SSH或者SSI其他第三方非Spring 4的项目中可能没有对其进行支持,所以不能说项目里面有了Spring 4就能放心的使用这些最新的日期时间API来做日期转换。

Spring 4支持重复注解

Java8之前,在同一个作用域不能配置相同的注解,不然会提示唯一注解的错误。但是Java8以后,支持了重复的注解,即一个作用域上面同一个注解可以配置多次。代码如下:


@Configuration
@ComponentScan
@EnableAutoConfiguration
@PropertySource("classpath:/example1.properties")
@PropertySource("classpath:/example2.properties")
public class Application {

@Autowired
private Environment env;

@Bean
public JdbcTemplate template(DataSource datasource) {
    System.out.println(env.getProperty("test.prop1"));
    System.out.println(env.getProperty("test.prop2"));
    return new JdbcTemplate(datasource);
}

public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}
}

但是这里是要有意义的重复配置,而不是无聊的进行配置,比如你对@Autowired重复配置,这个我只能说很无聊咩!

Java 8 Optional<>在Spring 4.1的使用

我们在开发过程中,如果对一个方法返回结果,在不确定他是非空的时候,都要进行非空校验,以防止出现空指针异常。于是Java 8针对这种情况,提供了一个统一的处理,就是Optional。先看看怎么用它:

之前我们这样来进行空校验:


Customer customer = customerRepository.findCustomerById(“123”);
if(customer != null) {
    customer.getName(); // avoid a null pointer exception
}

java 8里利用Optional可以如下来做:


public interface CustomerRepository extends CrudRepository<Customer, Long> {
public Optional<Customer> findCustomerById(String id);
}


//在其他方法调用:
Optional<Customer> optional = customerRepository.findCustomerById(“123”);
if(optional.isPresent()) {
    Customer customer = optional.get();
    customer.getName();
}

个人感觉也没简单而已,只是没出现了null关键词,那Spring怎么来使用它的呢?Spring一般用在对Bean的注入的时候,当我们配置某个不是必须注入的,可以通过这种方式来用,具体代码如下:

之前代码:


@Service
public class MyService {

    @Autowired(required=false)
    OtherService otherService;

    public doSomething() {
      if(otherService != null) {
        // use other service
      }
    }
}

使用Optional之后:


public class MyService {

    @Autowired
    Optional<OtherService> otherService;

    public doSomething() {
      otherService.ifPresent( s ->  {
        // use s to do something
      });
    }
}

可以获取方法参数名

java 8之前,通过反射是无法获取方法参数名称的,Field只能获得类型,但是java 8以后将参数名称存储在了类文件中,于是可以通过反射获取方法参数的名称。这个对于我来说是一个惊喜,之前为了能够获取方法参数需要增加多少配置,弄得很是蹩脚,现在,可以放开脚步走了。带着这个特性,可以带来很多好处,下面列举出部分例子:

Java 8之前:


@RequestMapping("/accounts/{id}")
public Account getAccount(@PathVariable("id") String id)

Java 8之后:

@RequestMapping("/accounts/{id}")
public Account getAccount(@PathVariable String id)

不在指定参数名称了,只要保持你方法参数和引用的参数名称一样即可。是否小激动了一把?

又例如:

Java 8之前:


interface CustomerRepository extends CrudRepository<Customer, Long> {
@Query("select c from Customer c where c.lastname = :lastname")
List<Customer> findByLastname(@Param("lastname") String lastname);
}

Java 8之后:


interface CustomerRepository extends CrudRepository<Customer, Long> {
@Query("select c from Customer c where c.lastname = :lastname")
List<Customer> findByLastname(String lastname);
}

借助这篇文章也体验了一下Java 8的新特性。更多的特性还需真正引用的时候去发现。

你可能感兴趣的:(Java 8在Spring 4中的使用)