So basically what I am trying to do is the following:
Load Batch of Data from the Database
Map that data (Object[] query result) to a class representing the data in a readable format
Write to File
Repeat until query gets no more results
I listed the structures that I am familiar with that seem to fit the need and why they don't fit my needs.
Iterator → Has no option to map and filter without calling next()
I need to define the map function in a subclass though without actually having the data (similar to a stream), so that I can pass the "Stream" way up to a calling class and only there call next, which then calls all the map functions as a result
Stream → All data needs to be available before mapping and filtering is possible
Observable → Sends data as soon as it comes available. I need to process it in sync though
To get more of a feeling what I am trying to do, I made a small example:
// Disclaimer: "Something" is the structure I am not sure of now.
// Could be an Iterator or something else that fits (Thats the question)
public class Orchestrator {
#Inject
private DataGetter dataGetter;
public void doWork() {
FileWriter writer = new FileWriter("filename");
// Write the formatted data to the file
dataGetter.getData()
.forEach(data -> writer.writeToFile(data));
}
}
public class FileWriter {
public void writeToFile(List<Thing> data) {
// Write to file
}
}
public class DataGetter {
#Inject
private ThingDao thingDao;
public Something<List<Thing>> getData() {
// Map data to the correct format and return that
return thingDao.getThings()
.map(partialResult -> /* map to object */);
}
}
public class ThingDao {
public Something<List<Object[]>> getThings() {
Query q = ...;
// Dont know what to return
}
}
What I have got so far:
I tried to go from the base of an Iterator, because it's the only one that really fulfills my memory requirements. Then I have added some methods to map and loop over the data. It's not really a robust design though and it's going to be harder than I thought, so I wanted to know if there is anything out there already that does what I need.
public class QIterator<E> implements Iterator<List<E>> {
public static String QUERY_OFFSET = "queryOffset";
public static String QUERY_LIMIT = "queryLimit";
private Query query;
private long lastResultIndex = 0;
private long batchSize;
private Function<List<Object>, List<E>> mapper;
public QIterator(Query query, long batchSize) {
this.query = query;
this.batchSize = batchSize;
}
public QIterator(Query query, long batchSize, Function<List<Object>, List<E>> mapper) {
this(query, batchSize);
this.mapper = mapper;
}
#Override
public boolean hasNext() {
return lastResultIndex % batchSize == 0;
}
#Override
public List<E> next() {
query.setParameter(QueryIterator.QUERY_OFFSET, lastResultIndex);
query.setParameter(QueryIterator.QUERY_LIMIT, batchSize);
List<Object> result = (List<Object>) query.getResultList(); // unchecked
lastResultIndex += result.size();
List<E> mappedResult;
if (mapper != null) {
mappedResult = mapper.apply(result);
} else {
mappedResult = (List<E>) result; // unchecked
}
return mappedResult;
}
public <R> QIterator<R> map(Function<List<E>, List<R>> appendingMapper) {
return new QIterator<>(query, batchSize, (data) -> {
if (this.mapper != null) {
return appendingMapper.apply(this.mapper.apply(data));
} else {
return appendingMapper.apply((List<E>) data);
}
});
}
public void forEach(BiConsumer<List<E>, Integer> consumer) {
for (int i = 0; this.hasNext(); i++) {
consumer.accept(this.next(), i);
}
}
}
This works so far, but has some unchecked assignments which I do not really like and also I would like to have the ability to "append" one QIterator to another which is not hard by itself, but it should also take the maps that follow after the append.
Assume you have a DAO that provides data in a paginated manner, e.g. by applying the LIMIT and OFFSET clauses to the underlying SQL. Such a DAO class would have a method that takes those values as argument, i.e. the method would conform to the following functional method:
#FunctionalInterface
public interface PagedDao<T> {
List<T> getData(int offset, int limit);
}
E.g. calling getData(0, 20) would return the first 20 rows (page 1), calling getData(60, 20) would return the 20 rows on page 4. If the method returns less than 20 rows, it means we got the last page. Asking for data after the last row will return an empty list.
For the demo below, we can mock such a DAO class:
public class MockDao {
private final int rowCount;
public MockDao(int rowCount) {
this.rowCount = rowCount;
}
public List<SimpleRow> getSimpleRows(int offset, int limit) {
System.out.println("DEBUG: getData(" + offset + ", " + limit + ")");
if (offset < 0 || limit <= 0)
throw new IllegalArgumentException();
List<SimpleRow> data = new ArrayList<>();
for (int i = 0, rowNo = offset + 1; i < limit && rowNo <= this.rowCount; i++, rowNo++)
data.add(new SimpleRow("Row #" + rowNo));
System.out.println("DEBUG: data = " + data);
return data;
}
}
public class SimpleRow {
private final String data;
public SimpleRow(String data) {
this.data = data;
}
#Override
public String toString() {
return "Row[data=" + this.data + "]";
}
}
If you then want to generate a Stream of rows from that method, streaming all rows in blocks of a certain size, we need a Spliterator for that, so we can use StreamSupport.stream(Spliterator<T> spliterator, boolean parallel) to create a stream.
Here is an implementation of such a Spliterator:
public class PagedDaoSpliterator<T> implements Spliterator<T> {
private final PagedDao<T> dao;
private final int blockSize;
private int nextOffset;
private List<T> data;
private int dataIdx;
public PagedDaoSpliterator(PagedDao<T> dao, int blockSize) {
if (blockSize <= 0)
throw new IllegalArgumentException();
this.dao = Objects.requireNonNull(dao);
this.blockSize = blockSize;
}
#Override
public boolean tryAdvance(Consumer<? super T> action) {
if (this.data == null) {
if (this.nextOffset == -1/*At end*/)
return false; // Already at end
this.data = this.dao.getData(this.nextOffset, this.blockSize);
this.dataIdx = 0;
if (this.data.size() < this.blockSize)
this.nextOffset = -1/*At end, after this data*/;
else
this.nextOffset += data.size();
if (this.data.isEmpty()) {
this.data = null;
return false; // At end
}
}
action.accept(this.data.get(this.dataIdx++));
if (this.dataIdx == this.data.size())
this.data = null;
return true;
}
#Override
public Spliterator<T> trySplit() {
return null; // Parallel processing not supported
}
#Override
public long estimateSize() {
return Long.MAX_VALUE; // Unknown
}
#Override
public int characteristics() {
return ORDERED | NONNULL;
}
}
We can now test that using the mock DAO above:
MockDao dao = new MockDao(13);
Stream<SimpleRow> stream = StreamSupport.stream(
new PagedDaoSpliterator<>(dao::getSimpleRows, 5), /*parallel*/false);
stream.forEach(System.out::println);
Output
DEBUG: getData(0, 5)
DEBUG: data = [Row[data=Row #1], Row[data=Row #2], Row[data=Row #3], Row[data=Row #4], Row[data=Row #5]]
Row[data=Row #1]
Row[data=Row #2]
Row[data=Row #3]
Row[data=Row #4]
Row[data=Row #5]
DEBUG: getData(5, 5)
DEBUG: data = [Row[data=Row #6], Row[data=Row #7], Row[data=Row #8], Row[data=Row #9], Row[data=Row #10]]
Row[data=Row #6]
Row[data=Row #7]
Row[data=Row #8]
Row[data=Row #9]
Row[data=Row #10]
DEBUG: getData(10, 5)
DEBUG: data = [Row[data=Row #11], Row[data=Row #12], Row[data=Row #13]]
Row[data=Row #11]
Row[data=Row #12]
Row[data=Row #13]
As can be seen, we get 13 rows of data, retrieved from the database in blocks of 5 rows.
The data is not retrieved from the database until it is needed, causing low memory footprint, depending on block size and the stream operation not caching the data.
You can do it in one line as follows:
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(queryThatReturnsAllRowsOrdered);
Stream.generate(rs.next() ? map(rs) : null)
.takeWhile(Objects::nonNull)
.filter(<some predicate>)
.forEach(<some operation);
This starts processing when the first row is returned from the query and continues in parallel with the database until all rows have been read.
This approach only has one row in memory at a time, and minimises the load on the database by only running 1 query.
Mapping from a ResultSet is far more easy and natural than mapping from Object[] because you can access columns by name and with properly typed values, eg:
MyDao map(ResultSet rs) {
try {
String someStr = rs.getString("COLUMN_X");
int someInt = rs.getInt("COLUMN_Y"):
return new MyDao(someStr, someInt);
} catch (SQLException e ) {
throw new RuntimeException(e);
}
}
Related
When using Apache Spark with stateful processing, it can group rows with same key using flatMapGroupsWithState function
Dataset<Row> ds = spark.sql("SELECT ... FROM parquetTable")
.groupByKey(..., Encoders.STRING()
.flatMapGroupsWithState(new FlatMapFunctionEager(),
OutputMode.Append(),
Encoders.kryo(Session.class),
RowEncoder.apply(PARQUET_SCHEMA),
GroupStateTimeout.ProcessingTimeTimeout());
Generally, examples or tutorials show a FlatMapGroupsWithStateFunction with a List<Row> created first and iterator to it is returned:
private class FlatMapFunctionEager implements FlatMapGroupsWithStateFunction<String, Row, Session, Row> {
#Override
public Iterator<Row> call(String key, Iterator<Row> values, GroupState<Session> state) throws Exception {
Session session = null;
if (state.exists()) {
session = state.get();
} else {
session = createSession();
state.update(session);
}
// here a list is created and populated with results
List<Row> result = new LinkedList<>();
while (values.hasNext()) {
Row row = values.next();
result.add(process(row, session));
}
// here iterator of the list is returned
return result.iterator();
}
private Row process(Row row, Session session) {
// do processing and return generated row
}
}
However, this sometimes causes memory problems since Spark can group a lot of Rows for processing.
Is it safe to return a lazy iterator that stores Iterator and GroupState provided by the caller?
Or can Iterator and GroupState change after the call and therefore not safe to use them lazily?
Sample code:
public class FlatMapFunctionLazy implements FlatMapGroupsWithStateFunction<String, Row, Session, Row> {
#Override
public Iterator<Row> call(String key, Iterator<Row> values, GroupState<Session> state) throws Exception {
// here we pass the state and values iterator
return new LazyIterator(state, values);
}
}
public class LazyIterator implements Iterator<Row> {
private final GroupState<Session> state;
private final Iterator<Row> values;
public LazyIterator(GroupState<Session> state, Iterator<Row> values) {
this.state = state;
this.values = values;
}
#Override
public boolean hasNext() {
return values.hasNext();
}
#Override
public Row next() {
// here we use the provided iterator when our iterators next is called
Row row = values.next();
return process(row);
}
private Row process(Row row) {
Session session = null;
// here we query and update the state (GroupState)
if (state.exists()) {
session = state.get();
} else {
session = createSession();
state.update(session);
}
return process(row, session);
}
private Row process(Row row, Session session) {
// do processing and return generated row
}
}
Is this kind of usage safe or will be the behaviour undefined?
I tried lazy iterator with some sample input and got correct results however I could not be sure for its correctness since sometimes multi-threaded programs may produce correct results even though some race conditions exist and also documentation is not clear about this area.
I am new to java I want to optimize my code using Map in java. When I
write my Code I use lot of if else statement so I want reduce my code
using map of collection framework When I implement Map i am not get
accurate result. My Function totally not working. Here Is my code.
private List<Item> getBussinessSearchItem(IteamSearch itemSearch, byte searchType,int size, int offSet){
StringBuilder queryBuilder - new StringBuilder();
if(itemSearch.getOrigin()!=null && (checkOriginDomain(itemSearch.getOrigin))) {
if(itemSearch.getSort().equalsIgnoreCase("name")) {
if(itemSearch.getSortOrder() == 1) {
queryBuilder.append("ORDDER BY Name ASc");
}else {
queryBuilder.append("ORDDER BY Name ASc");
}
}else if(itemSearch.getSort().equalsIgnoreCase("upc1")) {
if(itemSearch.getSortOrder() == 1) {
queryBuilder.append("ORDDER BY upc1 ASc");
}else {
queryBuilder.append("ORDDER BY upc1 ASc");
}
}
else if(itemSearch.getSort().equalsIgnoreCase("minQuantiy")) {
if(itemSearch.getSortOrder() == 1) {
queryBuilder.append("ORDDER BY minQuantiy ASc");
}else {
queryBuilder.append("ORDDER BY minQuantiy ASc");
}
}
}
when I use this above statement it works fine and give me result
properly sorting with ASCENDING AND DESCINDING order. But I do not
want to implement above statement I want to implement map and that map
works same as the above statement.
Here is my code but this below code not working
private Map<String , String> getBussinessSearchItem(ItemSearch itemSearch){
Map<Srring,String> newMap = new HashMap<>();
itemSearch.getSort().equalsIgnoreCase("name");
itemSearch.getSort().equalsIgnoreCase("upc1");
itemSearch.getSort().equalsIgnoreCase("minQuantiy");
}
I do not know how to implement map instead of if else statement. I
want solve this issue using map or enum.
My ItemSerach table contain name,upc1,minquantity
If you move sort options to a separate class ItemSearchOrder class which implements equals and hashCode properly, you could use it directly as key in your map:
class ItemSearchOrder {
private final String sort;
private final int order;
public ItemSearchOrder(final String sort, final int order) {
this.sort = Objects.requireNonNull(sort);
this.order = order;
}
public static ItemSearchOrder asc(final String sort) {
return new ItemSearchOrder(sort, 1);
}
public static ItemSearchOrder desc(final String sort) {
return new ItemSearchOrder(sort, 0);
}
#Override
public boolean equals(final Object other) {
if (other == null) return false;
if (other == this) return true;
if (other.getClass() != this.getClass()) return false;
return this.order == other.order
&& this.sort.equalsIgnoreCase(other.sort);
}
#Override
public int hashCode() {
return Objects.hash(sort, order);
}
}
Then build your map:
final Map<ItemSearchOrder, String> sortQueries = Map.ofEntries(
Map.entry(ItemSearchOrder.asc("name")), "ORDER BY name ASC"),
Map.entry(ItemSearchOrder.desc("name")), "ORDER BY name DESC"),
Map.entry(ItemSearchOrder.asc("upc1")), "ORDER BY upc1 ASC"),
...
);
And then use it to look up the correct ORDER BY clause:
public List<Item> getBussinessSearchItem(
final IteamSearch itemSearch, ...) {
final String sort = sortQueries.get(itemSearch.getOrder());
if (sort == null) {
// unknown sort
}
// ...
}
I have a java stream of undefined length. Now I need to load some meta data from the database and assign it to the streamed data.
I cannot:
load all data from the stream to my RAM at once, populate the metadata and then start a new stream as this might use to much RAM.
load the metadata for each element individually as this would flood my database with too many requests.
Thus I thought I could load the metadata in partitions from the database.
I need a method like this:
<T> Stream<List<T>> partition(Stream<T> stream, int partitionSize)
so I can use it like this
partition(dataSource.stream(), 1000)
.map(metadataSource::populate)
.flatMap(List::stream)
.forEach(this::doSomething);
I already found Guava's Iteralbes#partition but that would force me to convert the stream to an iterable, partition it and convert it to a stream again. Is there something inbuilt for the stream partitioning or is there an easy way to implement it myself?
I haven't found an existing method that does this already, so I implemented one myself:
public class Partitioner<E> implements Iterator<List<E>> {
private final Iterator<E> iterator;
private final int partitionSize;
public static <T> Stream<List<T>> partition(final Stream<T> stream, final int partitionSize) {
return new Partitioner<>(stream, partitionSize).asStream();
}
public Partitioner(final Stream<E> stream, final int partitionSize) {
this(stream.iterator(), partitionSize);
}
public Partitioner(final Iterator<E> iterator, final int partitionSize) {
this.iterator = iterator;
this.partitionSize = partitionSize;
}
#Override
public boolean hasNext() {
return this.iterator.hasNext();
}
#Override
public List<E> next() {
if (!hasNext()) {
throw new NoSuchElementException("No more elements");
}
final ArrayList<E> result = new ArrayList<>(this.partitionSize);
for (int i = 0; i < this.partitionSize && hasNext(); i++) {
result.add(this.iterator.next());
}
return result;
}
public Stream<List<E>> asStream() {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(this, Spliterator.NONNULL), false);
}
}
At first my question is how to let a newly added row flash in JavaFx, then I went through a lot of questions related to this topic (such as javafx: table row flashing). Most of them are using setRowFactory and override the updateItem method by adding a Timeline animation which change the state of pseudoClass of the row.
Below is my code, I am trying to building a FlashControl which can be reused.
public class TableFlashControl<T> {
private PseudoClass flashHighlight = PseudoClass.getPseudoClass("flash-highlight");
private List<T> newAdded = new ArrayList<>();
private boolean isFilterApplied = false;
private boolean isSorted = false;
public void setIsFilterApplied(boolean isFilterApplied) {
this.isFilterApplied = isFilterApplied;
}
public void add(TableView<T> table){
ListChangeListener<T> change = c -> {
while (c.next()) {
if (c.wasAdded()) {
List<? extends T> added = c.getAddedSubList();
T lastAdded = added.get(0);
if (!isFilterApplied) {
newAdded.add(lastAdded);
}
}
}
};
table.getItems().addListener(change);
table.setRowFactory(param -> new TableRow<T>() {
#Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
return;
}
if (newAdded.contains(item)) {
if (isSorted) {
new Thread(()->{
Timeline flasher = new Timeline(
new KeyFrame(Duration.seconds(0.4), e -> pseudoClassStateChanged(flashHighlight, true)),
new KeyFrame(Duration.seconds(0.8), e -> pseudoClassStateChanged(flashHighlight, false))
);
flasher.setCycleCount(2);
flasher.play();
}).start();
if (item == newAdded.get(0)) {
newAdded.clear();
isSorted = false;
}
}else{
if(item == newAdded.get(0)){
isSorted = true;
}
}
}
}
});
}
}
Here ListChangeListener is associated with table.getItems() which helps me to record the newly inserted row.
It is possible to add multiple rows within one operation which means newAdded.size() can be larger than 1. What's more, rows are inserted from the top of the tableView(because I sort it with the Number.)
In tableView, not all rows are visible and updateItem methods only update those visible rows. My problem comes when these two situations happen(see below).
The first scenario
In first scenario, only 4 rows are visible, if user inserts 5 rows within one time, I cannot record the last row update(the updateItem won't be called for the new_row_5). Thereby, I cannot clear newAdded list (by doing newAdded.clear())
The second scenario
In the second scenario, only 4 rows are visible again. However, there are invisible rows both at top and bottom of the visible rows. If user inserts 2 rows, one will be visible and the other will be invisible. In my case, new_row_2 will flash while new_row_1 remains invisible. If user scrolls up the tableView when new_row_2 is flashing, he will see new_row_2 is flashing while new_row_1 is not which is really weird.
I also want to know if there is any way to find the number of visible rows.
I am still new to JavaFx and I don't know if this method is good or not. I hope someone can help me fix my problems. Thanks a lot!
Your approach doesn't seem like a clean way to do this. The animation depends on the TableRow the item is positioned in and does not seem to support multiple animations happening at the same time. Furthermore it relies on the equals method of the item class not being overridden and on the user not adding a item multiple times to the TableView. Also you potentially create a large number of Timelines (not necessary to start them from a seperate thread btw, since Timeline.play() does not block).
It's better to make the animation depend on the indices. Also keeping track of the TableRows created allows you to access existing cells, should they be be assigned a index that needs to be animated. Also you could handle the animations using a single AnimationTimer by storing the data in a suitable data structure.
Also it would IMHO be most convenient to use the rowFactory class to implement this logic.
The following example makes the rows flash whether they are on-screen or not.
public class FlashTableRowFactory<T> implements Callback<TableView<T>, TableRow<T>> {
private final static PseudoClass FLASH_HIGHLIGHT = PseudoClass.getPseudoClass("flash-highlight");
public FlashTableRowFactory(TableView<T> tableView) {
tableView.getItems().addListener((ListChangeListener.Change<? extends T> c) -> {
while (c.next()) {
if (c.wasPermutated()) {
int from = c.getFrom();
int to = c.getTo();
permutationUpdate(scheduledTasks, c, from, to);
permutationUpdate(unscheduledTasks, c, from, to);
}
if (c.wasReplaced()) {
addRange(c.getFrom(), c.getTo());
} else if (c.wasRemoved()) {
int from = c.getFrom();
int removed = c.getRemovedSize();
removeRange(scheduledTasks, from, from + removed);
removeRange(unscheduledTasks, from, from + removed);
modifyIndices(unscheduledTasks, from, -removed);
modifyIndices(scheduledTasks, from, -removed);
} else if (c.wasAdded()) {
int from = c.getFrom();
int to = c.getTo();
modifyIndices(unscheduledTasks, from, to - from);
modifyIndices(scheduledTasks, from, to - from);
addRange(from, to);
}
}
// remove all flashTasks that are older than the youngest for a
// given index
Set<Integer> indices = new HashSet<>();
removeDuplicates(unscheduledTasks, indices);
removeDuplicates(scheduledTasks, indices);
flashingIndices.clear();
updateFlash(lastUpdate);
refreshFlash();
if (!unscheduledTasks.isEmpty()) {
flasher.start();
}
});
this.tableView = tableView;
}
private static void removeDuplicates(List<FlashTask> list, Set<Integer> found) {
for (Iterator<FlashTask> iterator = list.iterator(); iterator.hasNext();) {
FlashTask next = iterator.next();
if (!found.add(next.index)) {
iterator.remove();
}
}
}
private static void modifyIndices(List<FlashTask> list, int minModify, int by) {
for (FlashTask task : list) {
if (task.index >= minModify) {
task.index += by;
}
}
}
private void addRange(int index, int to) {
for (; index < to; index++) {
unscheduledTasks.add(new FlashTask(index));
}
}
private static void removeRange(List<FlashTask> list, int from, int to) {
for (Iterator<FlashTask> iterator = list.iterator(); iterator.hasNext();) {
FlashTask next = iterator.next();
if (next.index >= from && next.index < to) {
iterator.remove();
}
}
}
private static void permutationUpdate(List<FlashTask> list, ListChangeListener.Change<?> c, int from, int to) {
for (FlashTask task : list) {
if (task.index < to && task.index >= from) {
task.index = c.getPermutation(task.index);
}
}
}
// set of item indices that should flash
private final Set<Integer> flashingIndices = new HashSet<>();
// references to every row created by this factory
private final List<SoftReference<TableRow<T>>> rows = new LinkedList<>();
// tasks waiting to be scheduled
private final List<FlashTask> unscheduledTasks = new LinkedList<>();
// tasks currently being animated
private final List<FlashTask> scheduledTasks = new LinkedList<>();
private static class FlashTask {
int index;
long schedulingTime;
public FlashTask(int index) {
this.index = index;
}
}
private final TableView<T> tableView;
private long lastUpdate;
/**
* Updates flashingIndices set
* #param now the current timestamp
* #return true if the set has been modified, otherwise false.
*/
private boolean updateFlash(long now) {
boolean modified = false;
for (Iterator<FlashTask> iterator = scheduledTasks.iterator(); iterator.hasNext();) {
FlashTask next = iterator.next();
// running time in seconds
double runningTime = (now - next.schedulingTime) / (1000d * 1000d * 1000d);
// slows down the animation for demonstration
final double animationSpeed = 0.1;
if (runningTime < 0.4 / animationSpeed) {
// no need to handle tasks that run for less than 0.4 seconds
break;
} else if (runningTime > 1.6 / animationSpeed) {
// end of task reached
iterator.remove();
modified |= flashingIndices.remove(next.index);
} else if (runningTime > 0.8 / animationSpeed && runningTime < 1.2 / animationSpeed) {
// second "inactive" interval during animation
modified |= flashingIndices.remove(next.index);
} else {
// activate otherwise
modified |= flashingIndices.add(next.index);
}
}
return modified;
}
private final AnimationTimer flasher = new AnimationTimer() {
#Override
public void handle(long now) {
lastUpdate = now;
// activate waiting flash tasks
for (FlashTask task : unscheduledTasks) {
task.schedulingTime = now;
}
scheduledTasks.addAll(unscheduledTasks);
unscheduledTasks.clear();
if (updateFlash(now)) {
refreshFlash();
if (scheduledTasks.isEmpty()) {
// stop, if there are no more tasks
stop();
}
}
}
};
/**
* Sets the pseudoclasses of rows based on flashingIndices set
*/
private void refreshFlash() {
for (Iterator<SoftReference<TableRow<T>>> iterator = rows.iterator(); iterator.hasNext();) {
SoftReference<TableRow<T>> next = iterator.next();
TableRow<T> row = next.get();
if (row == null) {
// remove references claimed by garbage collection
iterator.remove();
} else {
row.pseudoClassStateChanged(FLASH_HIGHLIGHT, flashingIndices.contains(row.getIndex()));
}
}
}
#Override
public TableRow<T> call(TableView<T> param) {
if (tableView != param) {
throw new IllegalArgumentException("This factory can only be used with the table passed to the constructor");
}
return new FlashRow();
}
private class FlashRow extends TableRow<T> {
{
rows.add(new SoftReference<>(this));
}
#Override
public void updateIndex(int i) {
super.updateIndex(i);
// update pseudoclass based on flashingIndices set
pseudoClassStateChanged(FLASH_HIGHLIGHT, flashingIndices.contains(i));
}
}
}
I'm frequently using the do-while-checkNextForNull-getNext looping pattern (don't know if there is an official name for it) in some of my projects. But in Java8, the use of Optional is considered as cleaner code than checking for null references in client-code. But when using Optional in this looping pattern, the code gets a bit verbose and ugly, but because Optional has some handy methodS, I would expect that there must exist a cleaner way than the one I came up with below.
Example:
Given the following class.
class Item {
int nr;
Item(nr) {
this.nr = nr;
// an expensive operation
}
Item next() {
return ...someCondition....
? new Item(nr + 1)
: null;
}
}
In which the first item always has nr==1 and each item determines the next item, and you don't want to create unnecessary new items.
I can use the following looping do-while-checkNextForNull-getNext pattern in client-code:
Item item = new Item(1);
do {
// do something with the item ....
} while ((item = item.next()) != null);
With Java8-Optional, the given class becomes:
class Item {
....
Optional<Item> next() {
return ...someCondition....
? Optional.of(new Item(nr + 1))
: Optional.empty();
}
}
And then the do-while-checkNextForNull-getNext looping pattern becomes a bit ugly and verbose:
Item item = new Item(1);
do {
// do something with the item ....
} while ((item = item.next().orElse(null)) != null);
The orElse(null)) != null part feels uncomfortable.
I have looked for other kind of loops, but haven't found a better one. Is there a cleaner solution?
Update:
It is possible to use a for-each loop while at the same time avoiding null-references (the use of null-references is considered as a bad practice). This solution has been proposed by Xavier Delamotte, and doesn't need Java8-Optional.
Implementation with a generic iterator:
public class Item implements Iterable<Item>, Iterator<Item> {
int nr;
Item(int nr) {
this.nr = nr;
// an expensive operation
}
public Item next() {
return new Item(nr + 1);
}
public boolean hasNext() {
return ....someCondition.....;
}
#Override
public Iterator<Item> iterator() {
return new CustomIterator(this);
}
}
and
class CustomIterator<T extends Iterator<T>> implements Iterator<T> {
T currentItem;
boolean nextCalled;
public CustomIterator(T firstItem) {
this.currentItem = firstItem;
}
#Override
public boolean hasNext() {
return currentItem.hasNext();
}
#Override
public T next() {
if (! nextCalled) {
nextCalled = true;
return currentItem;
} else {
currentItem = currentItem.next();
return currentItem;
}
}
}
Then client code becomes very simple/clean:
for (Item item : new Item(1)) {
// do something with the item ....
}
Although this may be seen as a violation of the Iterator contract because the new Item(1) object is included in the loop, whereas normally, the for loop would immediately call next() and thus skipping the first object. In other words: for the first object, next() is violated because it returnS the first object itself.
You can do something like this :
Optional<Item> item = Optional.of(new Item(1));
do {
Item value = item.get();
// do something with the value ....
} while ((item = value.next()).isPresent());
or (to avoid the extra variable) :
Optional<Item> item = Optional.of(new Item(1));
do {
// do something with item.get() ....
} while ((item = item.get().next()).isPresent());
in Java8, the use of Optional is considered as cleaner code than checking for null references in client-code
No, it is the other way around: Optional can be used where it helps write cleaner code. Where it doesn't, just stick to the old idiom. Do not feel any pressure to use it if your existing idiom looks fine—and it does, in my opinion. As an example, this would be good usage of the Optional:
item.next().map(Object::toString).ifPresent(System.out::println);
Since you need to break out of the loop on the first non-present Optional, this doesn't really help.
However, I assume your true interest is more general: leveraging the features of Java 8 for your code. The abstraction you should pick is the Stream:
itemStream(() -> new Item(1)).forEach(item -> { ... all you need ... });
And, naturally, you can now go wild with stream processing:
itemStream(() -> new Item(1)).filter(item.nr > 3).mapToInt(Item::nr).sum();
This is how you would construct the stream:
import java.util.Spliterators;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class ItemSpliterator extends Spliterators.AbstractSpliterator<Item>
{
private Supplier<Item> supplyFirst;
private Item lastItem;
public ItemSpliterator(Supplier<Item> supplyFirst) {
super(Long.MAX_VALUE, ORDERED | NONNULL);
this.supplyFirst = supplyFirst;
}
#Override public boolean tryAdvance(Consumer<? super Item> action) {
Item item;
if ((item = lastItem) != null)
item = lastItem = item.next();
else if (supplyFirst != null) {
item = lastItem = supplyFirst.get();
supplyFirst = null;
}
else return false;
if (item != null) {
action.accept(item);
return true;
}
return false;
}
public static Stream<Item> itemStream(Supplier<Item> supplyFirst) {
return StreamSupport.stream(new ItemSpliterator(supplyFirst), false);
}
}
With this you are a tiny step away from the ability to seamlessly parallelize your computation. Since your item stream is fundamentally sequential, I suggest looking into my blog post on this subject.
Just add the loop support to your API:
class Item {
int nr;
Item(int nr) {
this.nr = nr;
// an expensive operation
}
public void forEach(Consumer<Item> action) {
for(Item i=this; ; i=new Item(i.nr + 1)) {
action.accept(i);
if(!someCondition) break;
}
}
public Optional<Item> next() {
return someCondition? Optional.of(new Item(nr+1)): Optional.empty();
}
}
Then you can simply iterate via lambda expression
i.forEach(item -> {whatever you want to do with the item});
or method references
i.forEach(System.out::println);
If you want to support more sophisticated operations than just forEach loops, supporting streams is the right way to go. It’s similar in that your implementation encapsulates how to iterate over the Items.
Dropping another alternative here that is available since Java 9.
Stream.iterate(new Item(1), Item::hasNext, Item::next)
.forEach(this::doSomething)
Where doSomething(Item item) is the method that does something with the item.
Since this is related to some kind of design i come up with below design.
Create interface which support to provide optional next.
public interface NextProvidble<T> {
Optional<T> next();
}
Item implement NextProvidble interface.
public class Item implements NextProvidble<Item> {
int nr;
Item(int nr) {
this.nr = nr;
// an expensive operation
}
#Override
public Optional<Item> next() {
return /*...someCondition....*/ nr < 10 ? Optional.of(new Item(nr + 1)) : Optional.empty();
}
#Override
public String toString() {
return "NR : " + nr;
}
}
Here i use /...someCondition..../ as nr < 10
And new class for Custom Do While as below.
public abstract class CustomDoWhile<T extends NextProvidble<T>> {
public void operate(T t) {
doOperation(t);
Optional<T> next = t.next();
next.ifPresent( nextT -> operate(nextT));
}
protected abstract void doOperation(T t);
}
Now what you have to done in your client code.
new CustomDoWhile<Item>() {
#Override
protected void doOperation(Item item) {
System.out.println(item.toString());
}
}.operate(new Item(1));
It may very clear.
Please add your thoughts.