如何写一个正确的iterator

我们知道, iterator 是一个可变对象, 换句话来说, 它的next方法是有副作用的。
 对于那些由容器产生的iterator来说, hasNext一般都是没有副作用的。但是, 某些时候, hasNext也是可能有副作用的。举个例子来说, 如果我们要基于BufferedReader来写一个可以迭代行的迭代器, 我们就要在hashNext里面尝试读取新的一行, 于是, 副作用就产生了。 

当我们的hasNext方法是有副作用的时候, 就要特别小心了。因为用户有可能会连续多次调用hasNext这个方法!

同时,我们还要考虑一个问题。 一般情况下, 我们理想的迭代器使用方法是这样的

if (iter.hasNext) { val v = iter.next; 使用v来做一些事情 } else {退出迭代过程}
if (iter.hasNext) { val v = iter.next; 使用v来做一些事情 } else {退出迭代过程}
if (iter.hasNext) { val v = iter.next; 使用v来做一些事情 } else {退出迭代过程}

......


也就是说, 我们的迭代器的正确性依赖于 hasNext, next, hasNext, next....这个“合理的”调用序列
但是, 事实上, 用户其实并不一定会按照这种正确的调用顺序来使用我们的迭代器。

为了实现一个可以让用户随意安排调用序列, 我们要让迭代器满足两个性质:
1。任何时候, 任意两次连续的hasNext方法, 总是等价于一次hasNext
2。任何时候, 任意两次连续的next方法, 都等价于在这两个next方法中间插入一个hasNext方法

所谓的“a等价于b”, 就是说, 无论是通过途径a还是途径b, iterator最后的内部状态 都是一样的。

 只要同时满足这两个性质, 就可以放心地把iterator的正确性 设计成 依赖于 hasNext, next, hasNext, next....这个“合理的”调用序列 。


可以发现, 对于基于容器(List,Map,Set等等)的iterator来说, 这两个性质是“天然地, 直接地, 简单地”就满足的。其原因在于:如果hasNext方法是无副作用的,那么上面的两个性质一定会满足

但是当我们要写一些并不是基于容器的迭代器的时候, 这时候hasNext方法有可能会有副作用, 我们就要注意检查是否满足上面两个条件了。


总结起来:

当作为iterator的编写者的时候: 我们要尽量让hasNext没有副作用,如果实在不行,就要注意验证是不是能够满足上面的两个性质. 

当作为iterator的使用者的时候: 我们要假定hasNext是有副作用的, 所以要严格按照hasNext, next ... 这个调用序列来使用别人写的iterator


最后,给出一个例子, 写一个可以迭代行的迭代器:


import java.io._

def toReader(fp: String, enc: String): Reader = new InputStreamReader(new FileInputStream(new File(fp)), enc)

def iLines(reader: Reader): Iterator[String] = {
    val br = new BufferedReader(reader)

    var curline = ""

    var checked = false
    var checkedRes = false

    new Iterator[String] {
        def hasNext: Boolean = {
            if (checked) return checkedRes
            
            checked = true
            curline = br.readLine()
            checkedRes = if (curline != null) true else false
            return checkedRes
        }

        def next: String = {
            if (!checked) this.hasNext
            
            checked = false
            return curline
        }
    }

} 

转载于:https://my.oschina.net/mustang/blog/91547

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常感谢您的提问!以下是一个简单的 Java 代码示例,可以用于将 Excel 文件导入到数据库中: ``` import java.io.File; import java.io.FileInputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Iterator; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; public class ExcelImporter { public static void main(String[] args) { String jdbcUrl = "jdbc:mysql://localhost:3306/mydatabase"; String username = "myusername"; String password = "mypassword"; String excelFilePath = "path/to/excel/file.xlsx"; String tableName = "mytable"; try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password)) { FileInputStream inputStream = new FileInputStream(new File(excelFilePath)); Workbook workbook = WorkbookFactory.create(inputStream); Sheet sheet = workbook.getSheetAt(0); Iterator<Row> rowIterator = sheet.iterator(); String sql = "INSERT INTO " + tableName + " (column1, column2, column3) VALUES (?, ?, ?)"; PreparedStatement statement = connection.prepareStatement(sql); int batchSize = 20; int count = 0; while (rowIterator.hasNext()) { Row row = rowIterator.next(); Cell cell1 = row.getCell(0); Cell cell2 = row.getCell(1); Cell cell3 = row.getCell(2); statement.setString(1, cell1.getStringCellValue()); statement.setString(2, cell2.getStringCellValue()); statement.setString(3, cell3.getStringCellValue()); statement.addBatch(); if (++count % batchSize == 0) { statement.executeBatch(); } } statement.executeBatch(); workbook.close(); inputStream.close(); System.out.println("Data imported successfully!"); } catch (SQLException | IOException e) { e.printStackTrace(); } } } ``` 请注意,这只是一个简单的示例,您需要根据您的具体需求进行修改和整。同时,您需要确保您已经正确地安装了 MySQL 数据库和相关的 JDBC 驱动程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值