I'm trying to paste the OneForOneStrategy into a simple Hello-Akka program, like so based on this documentation: http://doc.akka.io/docs/akka/2.3.2/java/fault-tolerance.html
private static SupervisorStrategy strategy = new OneForOneStrategy(10,
Duration.create("1 minute"),
new Function<Throwable, SupervisorStrategy.Directive>() {
#Override
public SupervisorStrategy.Directive apply(Throwable t) {
if (t instanceof ArithmeticException) {
return resume();
} else if (t instanceof NullPointerException) {
return restart();
} else if (t instanceof IllegalArgumentException) {
return stop();
} else {
return escalate();
}
}
}
);
#Override
public SupervisorStrategy supervisorStrategy() {
return strategy;
}
However, the resume/restart/stop/escalate method calls don't compile out of the box.
Why not?
Just add import listed below:
import static akka.actor.SupervisorStrategy.escalate;
import static akka.actor.SupervisorStrategy.restart;
import static akka.actor.SupervisorStrategy.resume;
import static akka.actor.SupervisorStrategy.stop;
I've resolved this issue. You just need to return SupervisorStrategy.resume(), SupervisorStrategy.restart() ... etc.
Related
I have an app where i have a TreeView which will have TreeItems holding a large number of leaf TreeItems. Having a huge number of TreeItems in the treeview hurts the performance of the app noticeably, to avoid that, what i will do, is i will allow only one non-leaf TreeItem to be expanded at a time, and once a TreeItem is folded, i will clear it's children, and load them asynchronously once needed (When the user expands the TreeItem).
The weird issue is, in this test below, when i first click the expand arrow on the treeitem, the children load fine, and if i fold it (which will clear children) and unfold it again, sometimes it works and others the program hogs and starts consuming 30% of the cpu for a couple of minutes then gets back running. What's weirder is that if i double click on the TreeItem to expand it (Not using the arrow) the hog starts right away, even at first program launch.
What could i be possibly doing wrong here?
PS:
Some of the code in the LazyTreeItem class is inspired by James_D's answer Here
I tried running the loadItems task on the fx thread(Not using the ItemLoader), but it didn't make any difference.
Same issue occurs using both JAVA 8 and JAVA 9
App.java
public class App extends Application {
private TreeView<Item> treeView = new TreeView<>();
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("TreeView Lazy Load");
primaryStage.setScene(new Scene(new StackPane(treeView), 300, 275));
initTreeView();
primaryStage.show();
}
private void initTreeView() {
treeView.setShowRoot(false);
treeView.setRoot(new TreeItem<>(null));
List<SingleItem> items = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
items.add(new SingleItem(String.valueOf(i)));
}
TreeItem<Item> parentItem = new TreeItem<>(new Item());
parentItem.getChildren().add(new LazyTreeItem(new MultipleItem(items)));
treeView.getRoot().getChildren().add(parentItem);
}
public static void main(String[] args) {
launch(args);
}
}
LazyTreeItem.java
public class LazyTreeItem extends TreeItem<Item> {
private boolean childrenLoaded = false;
private boolean isLoadingItems = false;
public LazyTreeItem(Item value) {
super(value);
// Unload data on folding to reduce memory
expandedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
flush();
}
});
}
#Override
public ObservableList<TreeItem<Item>> getChildren() {
if (childrenLoaded || !isExpanded()) {
return super.getChildren();
}
if (super.getChildren().size() == 0) {
// Filler node (will translate into loading icon in the
// TreeCell factory)
super.getChildren().add(new TreeItem<>(null));
}
if (getValue() instanceof MultipleItem) {
if (!isLoadingItems) {
loadItems();
}
}
return super.getChildren();
}
public void loadItems() {
Task<List<TreeItem<Item>>> task = new Task<List<TreeItem<Item>>>() {
#Override
protected List<TreeItem<Item>> call() {
isLoadingItems = true;
List<SingleItem> downloadSet = ((MultipleItem) LazyTreeItem.this.getValue()).getEntries();
List<TreeItem<Item>> treeNodes = new ArrayList<>();
for (SingleItem download : downloadSet) {
treeNodes.add(new TreeItem<>(download));
}
return treeNodes;
}
};
task.setOnSucceeded(e -> {
Platform.runLater(() -> {
super.getChildren().clear();
super.getChildren().addAll(task.getValue());
childrenLoaded = true;
isLoadingItems = false;
});
});
ItemLoader.getSingleton().load(task);
}
private void flush() {
childrenLoaded = false;
super.getChildren().clear();
}
#Override
public boolean isLeaf() {
if (childrenLoaded) {
return getChildren().isEmpty();
}
return false;
}
}
ItemLoader.java
public class ItemLoader implements Runnable {
private static ItemLoader instance;
private List<Task> queue = new ArrayList<>();
private Task prevTask = null;
private ItemLoader() {
Thread runner = new Thread(this);
runner.setName("ItemLoader thread");
runner.setDaemon(true);
runner.start();
}
public static ItemLoader getSingleton() {
if (instance == null) {
instance = new ItemLoader();
}
return instance;
}
public <T> void load(Task task) {
if (queue.size() < 1) {
queue.add(task);
}
}
#Override
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!queue.isEmpty()) {
Task task = queue.get(0);
if (task != prevTask) {
prevTask = task;
task.run();
queue.remove(task);
}
}
}
}
}
Model (Item.java, SingleItem.java, MultipleItem.java)
public class Item {
}
/****************************************************************
********** SingleItem ************
****************************************************************/
public class SingleItem extends Item {
private String id;
public SingleItem(String id) {
this.id = id;
}
public void setId(String id) {
this.id = id;
}
}
/****************************************************************
********** MultipleItem ************
****************************************************************/
public class MultipleItem extends Item {
private List<SingleItem> entries = new ArrayList<>();
public MultipleItem(List<SingleItem> entries) {
this.entries = entries;
}
public List<SingleItem> getEntries() {
return entries;
}
public void setEntries(List<SingleItem> entries) {
this.entries = entries;
}
}
The issue, as pointed out by #kleopatra, is caused by adding a large amount of children when there are one or more items selected. One way to fix this is to try and implement your own FocusModel, as the default FocusModel seems to be the source of the problem. Another, and in my opinion easier, way to create a workaround is to clear the selection before adding the large group of children; afterwards, you can re-select the items that were previously selected.
The way I went about doing this is by firing TreeModificationEvents with custom EventTypes. Also, I decided not to override isLeaf() inside my lazy TreeItem. I find it easier to use a placeholder TreeItem for when the parent TreeItem is a lazy branch. Since there is a placeholder the parent will register as a branch automatically.
Here's an example that browses the default FileSystem. To test if the solution worked I created a 100,000 file directory and opened it; there was no hang for me. Hopefully that means this can be adapted to your code.
Note: This example does remove the children when the branch is collapsed, just like you are doing in your code.
App.java
import java.nio.file.FileSystems;
import java.nio.file.Path;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.stage.Stage;
public class App extends Application {
private static String pathToString(Path p) {
if (p == null) {
return "null";
} else if (p.getFileName() == null) {
return p.toString();
}
return p.getFileName().toString();
}
#Override
public void start(Stage primaryStage) {
TreeView<Path> tree = new TreeView<>(new TreeItem<>());
tree.setShowRoot(false);
tree.setCellFactory(LazyTreeCell.forTreeView("Loading...", App::pathToString));
TreeViewUtils.installSelectionBugWorkaround(tree);
for (Path fsRoot : FileSystems.getDefault().getRootDirectories()) {
tree.getRoot().getChildren().add(new LoadingTreeItem<>(fsRoot, new DirectoryLoader(fsRoot)));
}
primaryStage.setScene(new Scene(tree, 800, 600));
primaryStage.show();
}
}
DirectoryLoader.java
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import javafx.scene.control.TreeItem;
public class DirectoryLoader implements Callable<List<? extends TreeItem<Path>>> {
private static final Comparator<Path> COMPARATOR = (left, right) -> {
boolean leftIsDir = Files.isDirectory(left);
if (leftIsDir ^ Files.isDirectory(right)) {
return leftIsDir ? -1 : 1;
}
return left.compareTo(right);
};
private final Path directory;
public DirectoryLoader(Path directory) {
this.directory = directory;
}
#Override
public List<? extends TreeItem<Path>> call() throws Exception {
try (Stream<Path> stream = Files.list(directory)) {
return stream.sorted(COMPARATOR)
.map(this::toTreeItem)
.collect(Collectors.toList());
}
}
private TreeItem<Path> toTreeItem(Path path) {
return Files.isDirectory(path)
? new LoadingTreeItem<>(path, new DirectoryLoader(path))
: new TreeItem<>(path);
}
}
LoadingTreeItem.java
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.function.Supplier;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.event.EventType;
import javafx.scene.control.TreeItem;
public class LoadingTreeItem<T> extends TreeItem<T> {
private static final EventType<?> PRE_ADD_LOADED_CHILDREN
= new EventType<>(treeNotificationEvent(), "PRE_ADD_LOADED_CHILDREN");
private static final EventType<?> POST_ADD_LOADED_CHILDREN
= new EventType<>(treeNotificationEvent(), "POST_ADD_LOADED_CHILDREN");
#SuppressWarnings("unchecked")
static <T> EventType<TreeModificationEvent<T>> preAddLoadedChildrenEvent() {
return (EventType<TreeModificationEvent<T>>) PRE_ADD_LOADED_CHILDREN;
}
#SuppressWarnings("unchecked")
static <T> EventType<TreeModificationEvent<T>> postAddLoadedChildrenEvent() {
return (EventType<TreeModificationEvent<T>>) POST_ADD_LOADED_CHILDREN;
}
private final Callable<List<? extends TreeItem<T>>> callable;
private boolean needToLoadData = true;
private CompletableFuture<?> future;
public LoadingTreeItem(T value, Callable<List<? extends TreeItem<T>>> callable) {
super(value);
this.callable = callable;
super.getChildren().add(new TreeItem<>());
addExpandedListener();
}
#SuppressWarnings("unchecked")
private void addExpandedListener() {
expandedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
needToLoadData = true;
if (future != null) {
future.cancel(true);
}
super.getChildren().setAll(new TreeItem<>());
}
});
}
#Override
public ObservableList<TreeItem<T>> getChildren() {
if (needToLoadData) {
needToLoadData = false;
future = CompletableFuture.supplyAsync(new CallableToSupplierAdapter<>(callable))
.whenCompleteAsync(this::handleAsyncLoadComplete, Platform::runLater);
}
return super.getChildren();
}
private void handleAsyncLoadComplete(List<? extends TreeItem<T>> result, Throwable th) {
if (th != null) {
Thread.currentThread().getUncaughtExceptionHandler()
.uncaughtException(Thread.currentThread(), th);
} else {
Event.fireEvent(this, new TreeModificationEvent<>(preAddLoadedChildrenEvent(), this));
super.getChildren().setAll(result);
Event.fireEvent(this, new TreeModificationEvent<>(postAddLoadedChildrenEvent(), this));
}
future = null;
}
private static class CallableToSupplierAdapter<T> implements Supplier<T> {
private final Callable<T> callable;
private CallableToSupplierAdapter(Callable<T> callable) {
this.callable = callable;
}
#Override
public T get() {
try {
return callable.call();
} catch (Exception ex) {
throw new CompletionException(ex);
}
}
}
}
LazyTreeCell.java
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeView;
import javafx.util.Callback;
public class LazyTreeCell<T> extends TreeCell<T> {
public static <T> Callback<TreeView<T>, TreeCell<T>> forTreeView(String placeholderText,
Callback<? super T, String> toStringCallback) {
return tree -> new LazyTreeCell<>(placeholderText, toStringCallback);
}
private final String placeholderText;
private final Callback<? super T, String> toStringCallback;
public LazyTreeCell(String placeholderText, Callback<? super T, String> toStringCallback) {
this.placeholderText = placeholderText;
this.toStringCallback = toStringCallback;
}
/*
* Assumes that if "item" is null **and** the parent TreeItem is an instance of
* LoadingTreeItem that this is a "placeholder" cell.
*/
#Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else if (item == null && getTreeItem().getParent() instanceof LoadingTreeItem) {
setText(placeholderText);
} else {
setText(toStringCallback.call(item));
}
}
}
TreeViewUtils.java
import java.util.ArrayList;
import java.util.List;
import javafx.beans.value.ChangeListener;
import javafx.event.EventHandler;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeItem.TreeModificationEvent;
import javafx.scene.control.TreeView;
public class TreeViewUtils {
public static <T> void installSelectionBugWorkaround(TreeView<T> tree) {
List<TreeItem<T>> selected = new ArrayList<>(0);
EventHandler<TreeModificationEvent<T>> preAdd = event -> {
event.consume();
selected.addAll(tree.getSelectionModel().getSelectedItems());
tree.getSelectionModel().clearSelection();
};
EventHandler<TreeModificationEvent<T>> postAdd = event -> {
event.consume();
selected.forEach(tree.getSelectionModel()::select);
selected.clear();
};
ChangeListener<TreeItem<T>> rootListener = (observable, oldValue, newValue) -> {
if (oldValue != null) {
oldValue.removeEventHandler(LoadingTreeItem.preAddLoadedChildrenEvent(), preAdd);
oldValue.removeEventHandler(LoadingTreeItem.postAddLoadedChildrenEvent(), postAdd);
}
if (newValue != null) {
newValue.addEventHandler(LoadingTreeItem.preAddLoadedChildrenEvent(), preAdd);
newValue.addEventHandler(LoadingTreeItem.postAddLoadedChildrenEvent(), postAdd);
}
};
rootListener.changed(tree.rootProperty(), null, tree.getRoot());
tree.rootProperty().addListener(rootListener);
}
private TreeViewUtils() {}
}
As implemented, the utility method that installs the workaround is tied to you using LoadingTreeItems in the TreeView. I couldn't think of a good way to make the solution general enough to apply to any arbitrary TreeView; for that, I believe creating a custom FocusModel would be necessary.
There is probably a better way to implement the LazyTreeCell by using a class to wrap the real data—like what you're doing with Item. Then you could have an actual placehoder Item instance that tells the TreeCell that it is a placeholder rather than relying on what type the parent TreeItem is. As it is, my implementation is likely brittle.
I'm building a GUI application in Java using an application framework (Netbeans Platform) which requires a large amount of nearly identical classes to implement extremely similar Action classes. I've spent a lot of time attempting to generate these actions programmatically. Although I'm able to generate the Actions, the framework utilizes annotations during compile time to generate other internal cache/data files which I've been unable to reproduce using a programmatic approach.
I'm wondering if code generation tools are a better solution, or perhaps some custom annotations which wrap the framework annotations. Perhaps something like Lombok, or maybe a maven plugin. But don't know where to start and am not sure if this is even a good path to explore. Ideally, I think it would be great to define the actions in a data file and generate the java code at compile time.
The project is open source, and a number of other actions are on github. Here is an example of what the template might look like, the pieces I would need to inject replaced with {{string}}, {{code}} and {{int}}:
// imports omitted
#ActionID(
category = {{string}},
id = {{string}})
#ActionRegistration(
iconBase = {{string}},
displayName = "resources.MessagesBundle#" + {{string}},
lazy = false)
#ActionReferences({
#ActionReference(
path = {{string}},
position = {{int}})
})
public final class {{string}} extends AbstractAction implements UGSEventListener {
public static final String ICON_BASE = {{string}};
private BackendAPI backend;
public SoftResetAction() {
this.backend = CentralLookup.getDefault().lookup(BackendAPI.class);
this.backend.addUGSEventListener(this);
putValue("iconBase", ICON_BASE);
putValue(SMALL_ICON, ImageUtilities.loadImageIcon(ICON_BASE, false));
putValue("menuText", {{string}});
putValue(NAME, {{string}});
}
#Override
public void UGSEvent(UGSEvent cse) {
java.awt.EventQueue.invokeLater(() -> setEnabled(isEnabled()));
}
#Override
public boolean isEnabled() {
{{code}}
}
#Override
public void actionPerformed(ActionEvent e) {
{{code}}
}
}
You should try a code generator like Telosys ( http://www.telosys.org/ )
This tool is designed for this kind of situation, you just have to create a template for each type of repetitive class and launch the generation.
For more information see the templating principles : http://www.telosys.org/templates.html
Everything is free and open source, so you can reuse existing templates and adapt them according to your needs.
Some interresting posts about this tool :
https://modeling-languages.com/telosys-tools-the-concept-of-lightweight-model-for-code-generation/
https://dzone.com/articles/telosys-a-code-generation-tool-by-laurent-guerin
You can design a public Action class for common using just like blow. This is only a section of sample code. If some modules has its own biz logical, you can implements this PubAction to any subclass.
import java.awt.event.ActionEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.swing.AbstractAction;
public abstract class PubAction
extends AbstractAction
implements AppEventListener
{
protected ActionInterceptor interceptor;
protected IExceptionHandler exceptionHandler;
protected IActionStatusJudge actionStatusJudge = null;
public static final String TOOLBAR_SHOWNAME_KEY = "TOOLBAR_SHOWNAME_KEY";
public PubAction()
{
setShowNameInToolbar(false);
}
public String getBtnName() {
return (String)getValue("Name");
}
public void setBtnName(String btnName) {
putValue("Name", btnName);
}
public void setCode(String code)
{
putValue("Code", code);
}
public void handleEvent(AppEvent event)
{
updateStatus();
}
public void updateStatus()
{
boolean isEnable = isActionEnable();
setEnabled(getActionStatusJudge() == null ? isEnable : getActionStatusJudge().isActionEnable(this, isEnable));
}
protected boolean isActionEnable() {
return true;
}
public void setShowNameInToolbar(boolean isShow)
{
putValue("TOOLBAR_SHOWNAME_KEY", isShow ? Boolean.TRUE : Boolean.FALSE);
}
public void actionPerformed(ActionEvent e) {
Logger.debug("Entering " + getClass().toString() + ".actionPerformed");
beforeDoAction();
try
{
if ((interceptor == null) || (interceptor.beforeDoAction(this, e)))
{
try
{
doAction(e);
if (interceptor != null) {
interceptor.afterDoActionSuccessed(this, e);
}
} catch (Exception ex) {
if ((interceptor == null) || (interceptor.afterDoActionFailed(this, e, ex)))
{
if (getExceptionHandler() != null)
{
processExceptionHandler(ex);
}
else if ((ex instanceof RuntimeException))
{
throw ((RuntimeException)ex);
}
throw new RuntimeException(ex);
}
}
}
}
finally
{
Logger.debug("Leaving " + getClass().toString() + ".actionPerformed");
}
}
protected void processExceptionHandler(Exception ex)
{
new ExceptionHandlerUtil().processErrorMsg4SpecialAction(this, getExceptionHandler(), ex);
}
protected void beforeDoAction()
{
Method[] ms = getClass().getMethods();
for (Method m : ms)
{
Class<?> clazz = m.getReturnType();
if (AbstractUIAppModel.class.isAssignableFrom(clazz)) {
try
{
AbstractUIAppModel model = (AbstractUIAppModel)m.invoke(this, null);
if (model == null)
return;
LoginContext ctx = model.getContext();
if (ctx == null)
break;
ShowStatusBarMsgUtil.showStatusBarMsg("", ctx);
} catch (IllegalArgumentException e) {
Logger.debug(e.getMessage());
} catch (IllegalAccessException e) {
Logger.debug(e.getMessage());
} catch (InvocationTargetException e) {
Logger.debug(e.getMessage());
}
}
}
}
public abstract void doAction(ActionEvent paramActionEvent) throws Exception;
public ActionInterceptor getInterceptor()
{
return interceptor;
}
public void setInterceptor(ActionInterceptor interceptor) {
this.interceptor = interceptor;
}
public IExceptionHandler getExceptionHandler() {
return exceptionHandler;
}
public void setExceptionHandler(IExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
}
public IActionStatusJudge getActionStatusJudge() {
return actionStatusJudge;
}
public void setActionStatusJudge(IActionStatusJudge actionStatusJudge) {
this.actionStatusJudge = actionStatusJudge;
}
}
How do I develop JUnit test for the BinaryTree class that I've written?
Please advise or provide examples so I can have better understand how to test binary tree in Junit.
package binaryTree;
import javax.xml.soap.Node;
public class BinaryTree<T extends Comparable<T>> implements BTree<T> {
private TreeNode root;
Node current = (Node) root;
#Override
public void insert(T value) {
if (root == null) {
root = new TreeNode(value);
} else if (value.compareTo(value()) < 0) {
root.getleft().insert(value);
} else {
root.right().insert(value);
}
}
#Override
public T value() {
if (this.root != null) {
return (T) this.root.value();
} else {
return null;
}
}
#Override
public BTree<T> left() {
if (this.root != null) {
return this.root.getleft();
} else {
return null;
}
}
#Override
public BTree<T> right() {
if (this.root != null) {
return this.root.right();
} else {
return null;
}
}
}
Definitely read the docs in #tpitsch's post. But here's a simple example to get you started.
import static org.junit.Assert.*;
import org.junit.Test;
// This test class contains two test methods
public class SimpleTest {
private int add(int a, int b) {
return a + b;
}
#Test public void test1() throws Exception
{
System.out.println("#Test1");
assertEquals(add(1, 1), 2);
}
#Test public void test2() throws Exception
{
System.out.println("#Test2");
assertEquals(add(100, -30), 70);
}
}
We're testing the function add.
Each function with the #Test annotation is a JUnit test method. Each test method is run as a separate JUnit test. Function names test1() and test2() are not important.
In a test method, you can place assertions such as assertEquals() that make sure the add function is running as expected.
I just want to ask, if it is possible to check if a void method "cancelled" itself by calling return;?
For example in my main I call calculate(myArray);, which is defined as follows:
public static void calculate(Object[] array) {
if (array == null)
return;
// do stuff
}
Is their a way to know, if it returned or not? My thoughts were making a "global" boolean which is changed to true right before we return and then check its value in main or just change the return type to something like int and when it returned at the beginning we use return -1; and at the end of the method return 0;
Both is possible but I think neither of them is very good style. Is there an alternative?
You are right that the practices you described are considered bad in Java (and other modern languages).
The most common acceptable practices for your scenario are:
Make the method throw an exception. Do this if the "failing" code path shouldn't happen under normal circumstances.
Make the method's return type bool to indicate success or failure. Do this if the "failing" code path can happen under normal circumstances as well.
No, you cannot. From The Oracle Java tutorials - Returning a Value from a Method:
Any method declared void doesn't return a value. It does not need to contain a return statement, but it may do so. In such a case, a return statement can be used to branch out of a control flow block and exit the method and is simply used like this:
return;
There is no way from method invocation to determine if the void method was completed by a fall-through block or a return; statement.
Most other methods includes a return type of boolean and returns false when something went wrong, or simply throws an IllegalArgumentException.
You can utilize publisher - listener pattern :)
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.List;
public class Sample {
private interface Event {
}
private static class ExitEvent implements Event {
}
private static class SucceedEvent implements Event {
}
private interface EventListener {
void eventPerformed(Event e);
}
private static List<EventListener> listeners = new LinkedList<EventListener>();
private static void addActionListener(EventListener l) {
listeners.add(l);
}
private static void fireEvent(Event event) {
for (EventListener l : listeners) {
l.eventPerformed(event);
}
}
public static void calculate(Object[] array) {
if (array == null) {
fireEvent(new ExitEvent());
return;
}
fireEvent(new SucceedEvent());
}
public static void main(String[] args) {
addActionListener(new EventListener() {
public void eventPerformed(Event e) {
if (e instanceof ExitEvent) {
System.out.println("Exit");
} else if (e instanceof SucceedEvent) {
System.out.println("Success");
}
}
});
calculate(null);
calculate(new Object[] {});
}
}
Output:
Exit
Success
You can go much farther and remove those ugly ifs, by utilizing visitor pattern
import java.util.LinkedList;
import java.util.List;
public class Sample {
private interface EventVisitor {
void visit(ExitEvent event);
void visit(SucceedEvent event);
}
private interface Event {
void accept(EventVisitor visitor);
}
private static class ExitEvent implements Event {
public void accept(EventVisitor visitor) {
visitor.visit(this);
}
}
private static class SucceedEvent implements Event {
public void accept(EventVisitor visitor) {
visitor.visit(this);
}
}
private interface EventListener {
void eventPerformed(Event e);
}
private static List<EventListener> listeners = new LinkedList<EventListener>();
private static void addActionListener(EventListener l) {
listeners.add(l);
}
private static void fireEvent(Event event) {
for (EventListener l : listeners) {
l.eventPerformed(event);
}
}
public static void calculate(Object[] array) {
if (array == null) {
fireEvent(new ExitEvent());
return;
}
fireEvent(new SucceedEvent());
}
public static void main(String[] args) {
addActionListener(new EventListener() {
public void eventPerformed(Event e) {
e.accept(new EventVisitor() {
public void visit(SucceedEvent event) {
System.out.println("Success");
}
public void visit(ExitEvent event) {
System.out.println("Exit");
}
});
}
});
calculate(null);
calculate(new Object[] {});
}
}
Output:
Exit
Success
I am working on some workflow and it is possible to raise many exceptions in that. I heard that we can keep all those possible exceptions in an Enum (Exception1, Exception2 ...) and use it. How can we do that using Enums in Java?
You can add the classes of exceptions with
enum EnumWithExceptions {
ENUM1(Exception1.class, Exception2.class),
ENUM2(Exception3.class);
private final Class<? extends Exception>[] exceptions;
private EnumWithExceptions(Class<? extends Exception>... exceptions) {
this.exceptions = exceptions;
}
public boolean matches(Exception e) {
for(Class<? extends Exception> e2: exceptions)
if (e2.isInstance(e)) return true;
return false;
}
}
} catch(Exception e){
if (ENUM1.matches(e)){
//do something
} else if(ENUM2.matches(e)) {
//do something
} else {
//do something
}
}
enum Fred {
SAM(AnException.class),
I(AnotherException.class),
AM(YetAnotherException.class)
;
private Throwable t;
Fred(Throwable throwable) {
this.t = throwable;
}
public Throwable getThrowable() {
return t;
}
}
...
throw Fred.SAM.getThrowable();
Why not store the exceptions in an ArrayList? Or if you want to name the index, you could use a HashMap.
import java.util.ArrayList;
import java.util.HashMap;
public final class ExceptionStorage {
private static int exceptionCount = 0;
private static HashMap<String, Exception> indexedExceptions = new HashMap<>();
private static ArrayList<Exception> exceptions = new ArrayList();
public static void addException(Exception e) {
exceptions.add(e);
}
public static void putException(Exception e) {
indexedExceptions.put("Exception" + (++exceptionCount), e);
}
public static ArrayList<Exception> getUnindexedExceptions() {
return this.exceptions;
}
public static HashMap<String, Exception> getIndexedExceptions() {
return this.indexedExceptions;
}
}
Obviously you would have to modify the code to use either ArrayList or HashMap, but I think this would be a better solution than using Enums.