Java Iterator backed by a ResultSet

后端 未结 17 694
清歌不尽
清歌不尽 2020-12-13 06:51

I\'ve got a class that implements Iterator with a ResultSet as a data member. Essentially the class looks like this:

public class A implements Iterator{
            


        
相关标签:
17条回答
  • 2020-12-13 07:30

    It can be done like this:

    public boolean hasNext() {
        ...
        return !entities.isLast();
        ...
    }
    
    0 讨论(0)
  • 2020-12-13 07:31

    It sounds like you are stuck between either providing an inefficient implementation of hasNext or throwing an exception stating that you do not support the operation.

    Unfortunately there are times when you implement an interface and you don't need all of the members. In that case I would suggest that you throw an exception in that member that you will not or cannot support and document that member on your type as an unsupported operation.

    0 讨论(0)
  • 2020-12-13 07:32
    public class A implements Iterator<Entity>
    {
        private final ResultSet entities;
    
        // Not required if ResultSet.isLast() is supported
        private boolean hasNextChecked, hasNext;
    
        . . .
    
        public boolean hasNext()
        {
            if (hasNextChecked)
               return hasNext;
            hasNext = entities.next();
            hasNextChecked = true;
            return hasNext;
    
            // You may also use !ResultSet.isLast()
            // but support for this method is optional 
        }
    
        public Entity next()
        {
            if (!hasNext())
               throw new NoSuchElementException();
    
            Entity entity = new Entity(entities.getString...etc....)
    
            // Not required if ResultSet.isLast() is supported
            hasNextChecked = false;
    
            return entity;
        }
    }
    
    0 讨论(0)
  • 2020-12-13 07:33

    I think there's enough decry over why it's a really bad idea to use ResultSet in an Iterator (in short, ResultSet maintains an active connection to DB and not closing it ASAP can lead to problems).

    But in a different situation, if you're getting ResultSet (rs) and are going to iterate over the elements, but you also wanted to do something before the iteration like this:

    if (rs.hasNext()) { //This method doesn't exist
        //do something ONCE, *IF* there are elements in the RS
    }
    while (rs.next()) {
        //do something repeatedly for each element
    }
    

    You can achieve the same effect by writing it like this instead:

    if (rs.next()) {
        //do something ONCE, *IF* there are elements in the RS
        do {
            //do something repeatedly for each element
        } while (rs.next());
    }
    
    0 讨论(0)
  • 2020-12-13 07:41

    Its not a really bad idea in the cases where you need it, it's just that you often do not need it.

    If you do need to do something like, say, stream your entire database.... you could pre-fetch the next row - if the fetch fails your hasNext is false.

    Here is what I used:

    /**
     * @author Ian Pojman <pojman@gmail.com>
     */
    public abstract class LookaheadIterator<T> implements Iterator<T> {
        /** The predetermined "next" object retrieved from the wrapped iterator, can be null. */
        protected T next;
    
        /**
         * Implement the hasNext policy of this iterator.
         * Returns true of the getNext() policy returns a new item.
         */
        public boolean hasNext()
        {
            if (next != null)
            {
                return true;
            }
    
            // we havent done it already, so go find the next thing...
            if (!doesHaveNext())
            {
                return false;
            }
    
            return getNext();
        }
    
        /** by default we can return true, since our logic does not rely on hasNext() - it prefetches the next */
        protected boolean doesHaveNext() {
            return true;
        }
    
        /**
         * Fetch the next item
         * @return false if the next item is null. 
         */
        protected boolean getNext()
        {
            next = loadNext();
    
            return next!=null;
        }
    
        /**
         * Subclasses implement the 'get next item' functionality by implementing this method. Implementations return null when they have no more.
         * @return Null if there is no next.
         */
        protected abstract T loadNext();
    
        /**
         * Return the next item from the wrapped iterator.
         */
        public T next()
        {
            if (!hasNext())
            {
                throw new NoSuchElementException();
            }
    
            T result = next;
    
            next = null;
    
            return result;
        }
    
        /**
         * Not implemented.
         * @throws UnsupportedOperationException
         */
        public void remove()
        {
            throw new UnsupportedOperationException();
        }
    }
    

    then:

        this.lookaheadIterator = new LookaheadIterator<T>() {
            @Override
            protected T loadNext() {
                try {
                    if (!resultSet.next()) {
                        return null;
                    }
    
                    // process your result set - I use a Spring JDBC RowMapper
                    return rowMapper.mapRow(resultSet, resultSet.getRow());
                } catch (SQLException e) {
                    throw new IllegalStateException("Error reading from database", e);
                }
            }
        };
    }
    
    0 讨论(0)
提交回复
热议问题