旅游网站排名相关推荐,注册qq空间网站,wordpress 发件邮箱,wordpress怎么提速Java 8中引入了Stream API和Lambda功能 #xff0c;使我们能够从JDBC ResultSet优雅地转换为仅提供映射功能的对象流。 这种功能当然可以是lambda。 基本上#xff0c;这个想法是使用ResultSet作为Supplier来生成Stream#xff1a; public class ResultSetSupplier impleme… Java 8中引入了Stream API和Lambda功能 使我们能够从JDBC ResultSet优雅地转换为仅提供映射功能的对象流。 这种功能当然可以是lambda。 基本上这个想法是使用ResultSet作为Supplier来生成Stream public class ResultSetSupplier implements SupplierT{private final ResultSet rs;private final FunctionResultSet, T mappingFunction;private ResultSetSupplier(ResultSet rs,FunctionResultSet, T mappingFunction) {this.rs rs;this.mappingFunction mappingFunction;}Overridepublic T get() {try {if (rs.next())return mappingFunction.apply(rs);} catch (SQLException e) {e.printStackTrace();}return null;}} 参数mappingFunction可能是lambda表达式用于从ResultSet构建T实例。 就像ActiveRecord模式一样此类ResultSet中的每一行都映射到T的实例其中列是T的属性。让我们考虑类City public class City{String city;String country;public City(String city, String country) {this.city city;this.country country;}public String getCountry() {return country;}Overridepublic String toString() {return City [city city , country country ;];}Overridepublic int hashCode() {final int prime 31;int result 1;result prime * result ((city null) ? 0 : city.hashCode());result prime * result ((country null) ? 0 : country.hashCode());return result;}Overridepublic boolean equals(Object obj) {if (this obj)return true;if (obj null)return false;if (getClass() ! obj.getClass())return false;City other (City) obj;if (city null) {if (other.city ! null)return false;} else if (!city.equals(other.city))return false;if (country null) {if (other.country ! null)return false;} else if (!country.equals(other.country))return false;return true;}} City对象的映射函数可以是lambda表达式如下所示 (ResultSet rs) - {try{return new City(rs.getString(city), rs.getString(country));} catch (Exception e) {return null;}} 我们假设数据库列分别称为city和country 。 尽管PreparedStatement和ResultSet都实现了AutoCloseable接口但必须提供resultSet才能创建对象流但在关闭流时也必须关闭此类resultSet。 一种可能的方法是使用代理来拦截对象流上的方法调用。 因此当在代理上调用close方法时它将在提供的resultSet上调用close 。 为了能够提供所有Stream功能所有方法调用也将在对象流上被调用。 使用代理很容易实现。 我们来看一下。 我们将有一个代理工厂和一个调用处理程序 public class ResultSetStreamInvocationHandlerT implements InvocationHandler{private StreamT stream; // proxy will intercept method calls to such streamprivate PreparedStatement st;private ResultSet rs;public void setup(PreparedStatement st, FunctionResultSet, T mappingFunction)throws SQLException{// PreparedStatement must be already setup in order// to just call executeQuery()this.st st;rs st.executeQuery();stream Stream.generate(new ResultSetSupplier(rs, mappingFunction));}Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {if (method null)throw new RuntimeException(null method null);// implement AutoCloseable for PreparedStatement// as calling close() more than once has no effectsif (method.getName().equals(close) args null){// invoked close(), no argumentsif (st ! null){st.close(); // closes ResultSet too}}return method.invoke(stream, args);}private class ResultSetSupplier implements SupplierT{private final ResultSet rs;private final FunctionResultSet, T mappingFunction;private ResultSetSupplier(ResultSet rs, FunctionResultSet, T mappingFunction) {this.rs rs;this.mappingFunction mappingFunction;}Overridepublic T get() {try {if (rs.next())return mappingFunction.apply(rs);} catch (SQLException e) {e.printStackTrace();}return null;}
}} 请注意如何使用invoke来拦截方法调用。 在接近的情况下被调用时 关闭调用的PreparedStatement为好。 对于每个调用的方法将在代理的流中调用相应的方法调用。 和工厂 public class ResultSetStreamT{SuppressWarnings(unchecked)public StreamT getStream(PreparedStatement st,FunctionResultSet, T mappingFunction) throws SQLException{final ResultSetStreamInvocationHandlerT handler new ResultSetStreamInvocationHandlerT();handler.setup(st, mappingFunction);StreamT proxy (StreamT) Proxy.newProxyInstance(getClass().getClassLoader(),new Class?[] {Stream.class},handler);return proxy;}
} 综上所述让我们编写一个简单的测试来显示用法。 Mockito将用于模拟PreparedStatement和ResultSet以避免对实际数据库运行测试。 public class ResultSetStreamTest {private class City{String city;String country;public City(String city, String country) {this.city city;this.country country;}public String getCountry() {return country;}Overridepublic String toString() {return City [city city , country country ];}Overridepublic int hashCode() {final int prime 31;int result 1;result prime * result getOuterType().hashCode();result prime * result ((city null) ? 0 : city.hashCode());result prime * result ((country null) ? 0 : country.hashCode());return result;}Overridepublic boolean equals(Object obj) {if (this obj)return true;if (obj null)return false;if (getClass() ! obj.getClass())return false;City other (City) obj;if (!getOuterType().equals(other.getOuterType()))return false;if (city null) {if (other.city ! null)return false;} else if (!city.equals(other.city))return false;if (country null) {if (other.country ! null)return false;} else if (!country.equals(other.country))return false;return true;}private ResultSetStreamTest getOuterType() {return ResultSetStreamTest.this;}}private String[][] data new String[][]{{Karachi, Pakistan},{Istanbul, Turkey},{Hong Kong, China},{Saint Petersburg, Russia},{Sydney, Australia},{Berlin, Germany},{Madrid, Spain}};private int timesCalled;private PreparedStatement mockPST;private ResultSet mockRS;Beforepublic void setup() throws SQLException{timesCalled -1;mockRS mock(ResultSet.class);mockPST mock(PreparedStatement.class);when(mockRS.next()).thenAnswer(new AnswerBoolean() {Overridepublic Boolean answer(InvocationOnMock invocation) throws Throwable {if (timesCalled data.length)return false;return true;}});when(mockRS.getString(eq(city))).thenAnswer(new AnswerString() {Overridepublic String answer(InvocationOnMock invocation) throws Throwable {return data[timesCalled][0];}});when(mockRS.getString(eq(country))).thenAnswer(new AnswerString() {Overridepublic String answer(InvocationOnMock invocation) throws Throwable {return data[timesCalled][1];}});when(mockPST.executeQuery()).thenReturn(mockRS);}Testpublic void simpleTest() throws SQLException{try (StreamCity testStream new ResultSetStreamCity().getStream(mockPST,(ResultSet rs) - {try {return new City(rs.getString(city), rs.getString(country));} catch (Exception e) {return null;}})){IteratorCity cities testStream.filter(city - !city.getCountry().equalsIgnoreCase(China)).limit(3).iterator();assertTrue(cities.hasNext());assertEquals(new City(Karachi, Pakistan), cities.next());assertTrue(cities.hasNext());assertEquals(new City(Istanbul, Turkey), cities.next());assertTrue(cities.hasNext());assertEquals(new City(Saint Petersburg, Russia), cities.next());assertFalse(cities.hasNext());}}} 在Github上下载完整的源代码。 翻译自: https://www.javacodegeeks.com/2014/09/creating-an-object-stream-from-a-jdbc-resultset.html