jdk1.8自定义Stream api.

    直接入正题,以下用数据库操作举例。

    查看ArrayList.stream()方法的实现,如图:

    发现方法实在Collection接口里面实现的,可以看出Stream对象是由StreamSupport.stream()方法初始化的。第一个入参是Spliterator实例,第二个入参,true表示执行的是并行操作,反之。查看api可以发现StreamSupport.Stream()方法还有另外一个以Suplier Function为数据源的重载方法,这里不举例。

    重新定位上图spliterator()方法,如图:

    查看this的类型:

    可以看到Spliterators.spliterator()方法的第一个入参是Iterator实例,第二个入参看文档貌似是用于适当分割数据源,增加批处理大小(batch size)的,填0的话,内部会替换为默认的数值,否则取自定义的值,这里不深究,当然也希望有大牛不吝解惑。

    好了,到这里就可以实现自己的Stream api了;

    直接上码:

    1. 创建实现Iterator接口:

package com.qkf.test.iterator;


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;

import com.qkf.test.bean.Record;

/**
 * 用于构建Stream的Source
 * @author qkf
 */
public class ResultSetIterator implements Iterator<Record> {

	private Connection conn;
	private ResultSet rs;
	private PreparedStatement ps;
	
	public ResultSetIterator(Connection conn, String sql, Object... params) {
		assert conn != null;
		assert sql != null;
		this.conn = conn;
		try {
			ps = conn.prepareStatement(sql);
			if (params != null && params.length > 0) {
				for (int i = 1; i <= params.length; ++i) {
					ps.setObject(i, params[i-1]);
				}
			}
			rs = ps.executeQuery();
		} catch (SQLException e) {
			closeRes();
			e.printStackTrace();
		}
	}
	
	@Override
	public boolean hasNext() {
		try {
			return rs.next();
		} catch (SQLException e) {
			closeRes();
			e.printStackTrace();
		}
		return false;
	}

	@Override
	public Record next() {
		return new Record(rs);
	}
	
	private void close(AutoCloseable... closeable) {
		if (closeable != null) {
			for (AutoCloseable c : closeable) {
					try {
						c.close();
					} catch (Exception e) {
						// nothing to do
					}
			}
		}
	}
	
	/**
	 * 关闭资源
	 */
	private void closeRes() {
		close(this.rs, this.ps, this.conn);
	}

}

    以上用到的Record类表示数据库的一行记录,上码:

package com.qkf.test.bean;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 表示数据行记录
 * @author qkf
 */
public class Record {
	
	private Map<String, Object> columnMap = null; // 行记录保存为key-value形式
	private List<Object> columnList = null; // 行记录保存为列表形式
	private int columnCount; // 行记录列数
	
	public Record(ResultSet rs) {
		columnMap = new HashMap<>();
		columnList = new ArrayList<>();
		try {
			ResultSetMetaData metaData = rs.getMetaData();
			columnCount = metaData.getColumnCount();
			if (columnCount > 0) {
				for (int i = 1; i <= columnCount; ++i) {
					Object obj = rs.getObject(i);
					columnList.add(obj);
					columnMap.put(metaData.getColumnLabel(i), obj);
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public Integer getAsInt(int index) {
		return Integer.valueOf(columnList.get(index).toString());
	}
	
	public Integer getAsInt(String name) {
		return Integer.valueOf(columnMap.get(name).toString());
	}
	
	public Double getAsDouble(int index) {
		return Double.valueOf(columnList.get(index).toString());
	}
	
	public Double getAsDouble(String name) {
		return Double.valueOf(columnMap.get(name).toString());
	}
	
	public String getAsString(int index) {
		return String.valueOf(columnList.get(index).toString());
	}
	
	public String getAsString(String name) {
		return String.valueOf(columnMap.get(name).toString());
	}
	
	public int getColumnSize() {
		return this.columnCount;
	}
	
	@Override
	public String toString() {
		return columnMap.toString();
	}
}

    2.根据开头阅读源码得到的Api自定义Stream api:

package com.qkf.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import com.qkf.test.bean.Record;
import com.qkf.test.iterator.ResultSetIterator;

/**
 * 数据库操作Stream api
 */
public class Records {
	
	public static Stream<Record> stream(String sql, Object... params) {
		try { // 注意: 这里使用try-with-resource处理Connection的话,数据库连接会提前关闭而导致以下读取数据库的操作抛异常
			Connection conn = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/users?useUnicode=true&characterEncoding=utf8", 
					"qkf", 
					"Fengqik@5811");
			return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
					new ResultSetIterator(conn, sql, params), 0), 
					false);
		} catch(Throwable e) {
			System.err.println("Connection refused!");
			return Stream.empty();
		}
	}
}

    OK, 以上就是本篇的全部代码,下面编写测试代码:

 测试数据:

    

    测试代码:

package com.qkf.test;

/**
 * test
 */
public class StreamTest {
	
	public static void before() {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
		} catch(Exception e) {}
	}
	
	public static void main(String[] args) {
		before();
		String sql = "select * from users where age <= ?";
		Records.stream(
				sql, 
				24 // sql params
		).peek(r -> {
			System.out.println("Record: " + r);
		}).filter(r -> 
			"男".equals(r.getAsString("sex"))
		).forEach(r -> System.out.println(
				String.format("hit: name: %s, age: %d", 
						r.getAsString("name"), 
						r.getAsInt(2)))
		);
	}
}

    运行结果:

    运行成功。

    总结一下:创建Stream实例由StreamSupport.stream(Spliterator实例, 是否并行); 而Spliterator实例可以通过Spliterators工厂类构造得到,本例使用的工厂方法入参是(自定义的Iterator类的实例, 特征(整形, characteristics));

     大概就这样。

    如有错误和不足,望斧正。

    晚了,睡觉。谢谢阅读。

转载于:https://my.oschina.net/u/2347651/blog/879293

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值