Return two Hashset from a Java method - java

I have this piece of code here that I want to transform in a method.
The problem is that I need the result of both hashes
How can I create a method that will return those two hashset (allPeopleFromTable and visibleInfo) ?
public method foo:
Set<People> allPeopleFromTable = new HashSet<>();
Set<People> visibleInfo = new HashSet<>();
for (ResultSet rs : resultSets) {
while (rs.next()) {
final Table people = new Table(rs);
allPeopleFromTable.add(people);
if (isVisible(people)) {
visibleInfo.add(people);
}
}
}
then in the main method I want to do
visibleInfo = getfoo(...)
allPeopleFromTable = getfoo (..)

One option is to pass them into the method:
void foo(Set<People> allPeopleFromTable, Set<People> visibleInfo) {
// add items to sets
}
Another option is return a list of sets:
List<Set<People>> foo() {
// create sets
return Arrays.asList(allPeopleFromTable, visibleInfo);
}
Or you can return a tuple class, like Entry:
Map.Entry<Set<People>, Set<People>> foo() {
// create sets
return Map.entry(allPeopleFromTable, visibleInfo);
}
The most "proper" approach would be to wrap them in a custom class.
record PeopleSets(Set<People> allPeopleFromTable, Set<People> visibleInfo) {}
PeopleSets foo() {
// create sets
return new PeopleSets(allPeopleFromTable, visibleInfo);
}
This example uses records, but you can use a conventional class if you're on an older version of Java.

Related

A correct way to override a built-in mapper in Wicket 6

Wicket 6 has a default compound request mapper: SystemMapper. It contains BookmarkableMapper. I need to override it, that is, use my own FancyBookmarkableMapper instead.
What I tried:
Copy SystemMapper class as a whole and change the following line
add(new BookmarkableMapper());
to
add(new FancyBookmarkableMapper());
But this way is very ugly and fragile upgrade-wise (although it seems to work). I mention it here just for the sake of completeness.
Using the fact that SystemMapper is ICompoundMapper, replace the mapper using add(), remove() and iterator() methods:
private SystemMapper customizeSystemMapper() {
final SystemMapper rootRequestMapper = (SystemMapper) getRootRequestMapper();
IRequestMapper originalBookmarkableMapper = null;
boolean afterBookmarkable = false;
List<IRequestMapper> mappersAfterBookmarkable = new ArrayList<>();
for (IRequestMapper mapper : rootRequestMapper) {
if (mapper.getClass() == BookmarkableMapper.class) {
if (originalBookmarkableMapper != null) {
throw new IllegalStateException("There are two BookmarkableMapper instances in the initial mappers list");
}
originalBookmarkableMapper = mapper;
afterBookmarkable = true;
} else {
if (afterBookmarkable) {
mappersAfterBookmarkable.add(mapper);
}
}
}
if (originalBookmarkableMapper == null) {
throw new IllegalStateException("There is no BookmarkableMapper in the initial mappers list");
}
for (IRequestMapper mapperToRemove : mappersAfterBookmarkable) {
rootRequestMapper.remove(mapperToRemove);
}
rootRequestMapper.remove(originalBookmarkableMapper);
rootRequestMapper.add(new FancyBookmarkableMapper());
for (IRequestMapper mapperToAdd : mappersAfterBookmarkable) {
rootRequestMapper.add(mapperToAdd);
}
return rootRequestMapper;
}
Not very nice too, although it works as well.
Build an implementation of ICompoundMapper and decorate SystemMapper instance with it. The only way to substitute the built-in mapper is to try to play with iterator() method:
#Override
public Iterator<IRequestMapper> iterator() {
return new Iterator<IRequestMapper>() {
private Iterator<IRequestMapper> originalIterator = delegate.iterator();
#Override
public boolean hasNext() {
return originalIterator.hasNext();
}
#Override
public IRequestMapper next() {
IRequestMapper nextMapper = originalIterator.next();
if (nextMapper != null && nextMapper.getClass() == BookmarkableMapper.class) {
nextMapper = bookmarkableMapperReplacement;
}
return nextMapper;
}
#Override
public void remove() {
originalIterator.remove();
}
};
}
However, this does NOT work, as SystemMapper#mapRequest() (actually defined in CompoundRequestMapper) uses mappers field directly and not via iterator() method.
The easiest way:
private SystemMapper customizeSystemMapper2() {
final SystemMapper rootRequestMapper = (SystemMapper) getRootRequestMapper();
rootRequestMapper.add(new FancyBookmarkableMapper());
return rootRequestMapper;
}
Here we add our mapper to the beginning of the list. It extends BookmarkableMapper and inherits its getCompatibilityScore(), so it has the same score as BookmarkableMapper has, and it is earlier in the list, so it takes precedence.
This item 4 actually works. The only thing that makes me ask this question is that actually, both mappers are in the internal list of SystemMapper for this approach. Is it guaranteed that my mapper (that was added later and has the same score) will take precedence (including future Wicket versions)?
The easiest (and official) way is to use WebApplication#mount(new FancyBookmarkableMapper () in YourApplication#init() method.
I'll check tomorrow your concern in 3)! Update: improved it with https://git1-us-west.apache.org/repos/asf?p=wicket.git;a=commitdiff;h=0eb63480;hp=5821157738ac43a09232a2aeb0fa2ff808340f4d
Please let us know if you see more improvements! Thank you!

How to DRY these block of code in Java?

Caller:
switch (type){
case "creature":
Creature returnActor2 = getNextCreature();
boolean isEat2 = actOnNearby(getRightChromosome(Config.HardCode.creature), returnActor2.getLocation());
if (isEat2) {
actOnCreature(returnActor2);
}
break;
case "monster":
Monster returnActor3 = getNextMonster();
boolean isEat3 = actOnNearby(getRightChromosome(Config.HardCode.monster), returnActor3.getLocation());
if (isEat3) {
actOnMonster(returnActor3);
}
break;
}
It will call the following 2 methods:
private Monster getNextMonster() {
ArrayList<Actor> nearbyActors = getActors();
Monster mine = new Monster();
for (Actor a : nearbyActors) {
if (a instanceof Monster) {
mine = (Monster) a;
}
}
return mine;
}
private Creature getNextCreature() {
ArrayList<Actor> nearbyActors = getActors();
Creature mine = new Creature();
for (Actor a : nearbyActors) {
if (a instanceof Creature) {
mine = (Creature) a;
}
}
return mine;
}
The question
As you can see, the getNextXXXXX() method are pretty the same, just return different object, the logic is same, how to DRY? the actOnXXXX() seems falls in the DRY category as well, but it all about the same, use same logic against different object. How to solve this?
Make it accept a classtype:
private <T> T getNext(Class<T> type) {
for (Actor a : getActors()) {
if (type.isAssignableFrom(a.getClass())) {
return (T) a;
}
}
return null; //or type.newInstance(); if you want a guaranteed object, but this restricts your constructor.
}
Or with Java 8:
private <T> T getNext(Class<T> type) {
return (T) getActors().stream()
.filter(a -> type.isAssignableFrom(a.getClass()))
.findFirst().orElse(null);
}
But the usage is the same:
Monster next = getNext(Monster.class);
Breaking down the problem, you know two categories of things:
What you need:
A next object of t type.
A way of determining if an object is t
type
What you have:
The type t you want
A collection of objects, one of which might be t type
A new object via a no-args constructor (or null) if none are there
Additionally, the only variance between all these methods is one thing: Which type it is. So we literally "make that a variable", and as such it becomes a method parameter.
Breaking this down we simply need to organize the code in a manner which accomplishes this:
method: //receives a "type" as a parameter
iterate the list of possible `t`s //our list of objects
if some_t == type //our comparison, previously `a instanceof Type`
return some_t //our result is found
return null //or a new object, but essentially our "default"
The only primary differences here were:
Replacing some_t instanceof Type with type.isAssignableFrom(some_t.getClass())
Reason being here that this is simply how you determine this when using Class<T>
Our default can either be null or a new object
Making the object dynamically via reflection restricts your options and has exceptions to deal with. Returning null or an empty Optional<T> would help signify that you did not have a result, and the caller can act accordingly. You could potentially also just pass the default object itself, and then go back to the instanceof check.
Asking yourself this same hypothesis of "what do I need, and what can I provide/have", will help you map out breaking down the problem into smaller steps, and solving the larger puzzle.
I think, there is a confusion in your code and logic.
FOr example, if you need to iterate on list, you dont need to create a new object. That is, in the following code snippet, "new Monster()" doesn't need to be written
Monster mine = null; // new Monster();
for (Actor a : nearbyActors) {
if (a instanceof Monster) {
mine = (Monster) a;
}
}
Anyway, the answer is the "Type Inference in Java."
https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html
The answer to your question is
package __TypeInference;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
new Main().doLogic();
}
private void doLogic() {
List<Actor> nearbyActors = getActors();
for (Actor actor : nearbyActors) {
// do with the next actor
System.out.println(actor.toString());
}
}
private List<Actor> getActors() {
List<Actor> actors = new ArrayList<Actor>();
actors.add(new Monster());
actors.add(new Creature());
actors.add(new Monster());
actors.add(new Creature());
return actors;
}
class Monster extends Actor {
#Override
public String toString() {
return "Monster";
}
}
class Creature extends Actor {
#Override
public String toString() {
return "Creatue";
}
}
class Actor {
}
}
I think what you want is to combine getNextMonster and getNextCreature because they have repeated code.
The best thing to do here is to write a generic method that does this:
private <T extends Actor> T getNextActor(T newActor) {
ArrayList<Actor> nearbyActors = getActors();
T mine = newActor;
for (Actor a : nearbyActors) {
if (a instanceof T) {
mine = (T) a;
}
}
return mine;
}
And you can call it like this:
// This is equivalent to calling getNextCreature()
getNextActor(new Creature());
// This is equivalent to calling getNextMonster()
getNextActor(new Monster());
Let me explain the code.
The new method returns a type of Actor. You tell it what kind of actor you want by passing the argument. The argument is necessary because you cannot just initialize a generic type argument like this:
new T();
Because the parameterless constructor might not be available. So that's the job of the caller.
I don't really know what I'm talking about...
This method has the following advantages:
It reduces repeated code
It is flexible - when you want to add another method called getNextXXX (where XXX is a subclass of Actor), you don't need to. Just call getNextActor(new XXX())!
It increases maintainability - if you want to change the implementation of getNextXXX, you can just change one method instead of 2.

How do I copy data from a collection of objects to a collection of different objects in Java8

I would like to use functional programming to copy data from a collection of one object to a collection of other objects.
I have been reading several Java 8 books and researching online. I am pretty sure I want to use stream(), but just about every example I have seen always iterates through a collection, does some processing on the objects in the collection, and uses println() to output the contents. No one seems to discuss how to deal with situations like the one described below.
Suppose we have the following objects:
public class ObjectA
{
private String someData;
private int moreData;
public String getSomeData()
{
return someData;
}
public void setSomeData(String sData)
{
someData = sData;
}
public int getMoreData()
{
return moreData;
}
public void setMoreData(int mData)
{
moreData = mData;
}
}
public class ObjectB
{
private String b_Data;
public String getB_Data()
{
return b_Data;
}
public void setB_Data(String bData)
{
b_Data = bData;
}
}
I want to create a collection of ObjectB objects whose b_data atributes are equal to the someData attributes in a collection of ObjectAs.
A reasonably good way to do this is illustrated in the code below:
public class Collector
{
public Collection<ObjectB> collectObjects(Collection<ObjectA> theAs)
{
// The use of an ArrayList is arbitrary. I might want to use any number
// of different lists or even different collections!
final Collection<ObjectB> theBs = new ArrayList<ObjectB>();
for(ObjectA obj : theAs)
{
final ObjectB bobj = new ObjectB();
bobj.setB_Data(obj.getSomeData());
theBs.add(bobj);
}
return theBs;
}
}
The code in the collectObjects() method will work, but it uses techniqhes of imperative programming. I would like to know how to make the collection of ObjectBs using functional techniques.
Is there a way to accomplish this using streams and lambdas?
This situation actually applies perfectly with the Stream API. What you want is to:
Make a Stream<ObjectA> which is a Stream of your input list, with theAs.stream().
Map each ObjectA in the Stream to an ObjectB with Stream.map.
Collect the result with Stream.collect into a new list using Collectors.toList().
This would be an implementation:
public Collection<ObjectB> collectObjects(Collection<ObjectA> theAs) {
return theAs.stream().map(obj -> {
final ObjectB bobj = new ObjectB();
bobj.setB_Data(obj.getSomeData());
return bobj;
}).collect(Collectors.toList());
}
Of course, you could create a constructor of ObjectB that takes obj.getSomeData() as parameter. It would simplify the code because then you could write:
public Collection<ObjectB> collectObjects(Collection<ObjectA> theAs) {
return theAs.stream().map(obj -> new ObjectB(obj.getSomeData())).collect(Collectors.toList());
}
obj -> new ObjectB(obj.getSomeData()) is called a lambda expression.
You can do it like this:
List<ObjectB> theBs = theAs
.stream()
.map(a-> {
final ObjectB bobj = new ObjectB();
bobj.setB_Data(a.getSomeData());
return bobj;
}).collect(Collectors.toList());
The a -> { ... } construct is a lambda, a construct that lets you pass some executable code into a method call.
The body of the lambda comes straight from the loop body in your second example.

How to retain information using a recursion in Java

Basically, every time I recurse, I reset the variable "path," but I need to keep that information. Also, I cannot pass it as a parameter. Is there a way to do this?
Here is the code I have now:
public List<Person> getDiseaseRouteTo(Person c){
List<Person> path = new LinkedList<Person>();
if (this.root == c) {
path.add(c);
} else if (this.root != c) {
path.add(this.root);
for (DiseaseTree child: this.getChildren()) {
if (child.contains(c)) {
path.add(child.getRoot());
return child.getDiseaseRouteTo(c);
}
}
}
return path;
}
Also, I cannot pass it as a parameter.
You can always create a private helper method where you can pass it:
public List<Person> getDiseaseRouteTo(Person c) {
List<Person> path = new LinkedList<Person>();
return getDiseaseRouteTo(c, path);
}
private List<Person> getDiseaseRouteTo(Person c, List<Person> path) {
// ...
}
You are creating a new instance of LinkedList every time you invoke the method.
You can create the path variable elsewhere, outside the scope of the getDiseaseRouteTo method, like janos suggested.

Write Java Comparator

I have created a Vector object to store data in Table object as Vector<Table>. Vector<Table> contains components as below.
[Vector<Record> records, String tableName, String keyColumnName, int recordCount, int columnCount]
I need to sort tableName in above Vector to my own order and return Vector<Table> with sorted tableNames for other processes.
I have wrote method as below.
private Vector<Table> orderTables(Vector<Table> loadTables) {
List<String> tableNames = new ArrayList<String>();
for (Table table : loadTables) {
String tblName = table.getTableName();
tableNames.add(tblName);
}
Collections.sort(tableNames, new MyComparable());
return null;
}
But I have no idea about how to write Comparator to this. My own sort order is stored in .properties file. I can read it and get value. But I have no idea about how to compare it.
How could I do it?
Before clarification
You need to write a Comparator for Table objects that delegates to the tableName's comparator:
new Comparator<Table>() {
#Override public int compare(Table one, Table two) {
return one.getTableName().compareTo(two.getTableName());
}
}
Note that this will consider Tables that have the same name to be equal. This can mess things up if you put these tables in a HashMap or HashSet. To avoid this, you can detect this case and return one.hashCode() - two.hashCode() if the table names are the same.
Guava's ComparisonChain is a convenient way to write such multi-stage comparisons:
new Comparator<Table>() {
#Override public int compare(Table one, Table two) {
return ComparisonChain.start()
.compare(one.getTableName(), two.getTableName())
.compare(one.hashCode(), two.hashCode())
.result();
}
}
After clarification
Okay, the question is to impose a predefined sorting order rather than sorting the Tables by name. In that case, you need to make a Comparator that is aware of the ordering defined in the .properties file.
One way to achieve this is to initialize a mapping of table names to sorting order indices, and refer that mapping during the comparison. Given the property value:
SORT_ORDER = SALES,SALE_PRODUCTS,EXPENSES,EXPENSES_ITEMS
The mapping should look like:
{
SALES: 0,
SALE_PRODUCTS: 1,
EXPENSES: 2,
EXPENSES_ITEMS: 3
}
Here's what the comparator would look like:
private static class PredefinedOrderComparator implements Comparator<Table> {
public PredefinedOrderComparator() {
// Initialize orderIndex here
}
private final Map<String, Integer> orderIndex;
#Override public int compare(Table one, Table two) {
return orderIndex.get(one.getTableName()) - orderIndex.get(two.getTableName());
}
}
To populate orderIndex from the property value, you need to:
Get the comma-separated list using getProperty() as you mentioned
Split that value on comma (I recommend using Guava's Splitter, but String.split or others will work too)
Initialize a new HashMap<String, Integer> and an int index = 0
Iterate through the split tokens, map the current token to index and increment index
Note the implicit assumption that none of the table names have a comma in it.
public class MyComparable implements Comparator<Table>{
#Override
public int compare(Table table1, Table table2) {
return (table1.getTableName().compareTo(table2.getTableName());
}
}
make sure that you have overridden the hashcode and equals in Table class to achieve this.
I wrote you a very simple example on how to work with a Comparator. If you create a class called Main, copy paste below contents in it, compile and run it, you can see what's going on.
A comparator just needs to implement an interface. For this it needs to implement one method (public int compare(T arg0, T arg1). There you specify how a collection will get sorted; in this case according to the alfabet.
I hope this helps you.
import java.util.*;
public class Main {
public static void main(String[] args) {
System.out.println("Start\n");
List<Item> items = new ArrayList<Item>();
for(String s : new String[]{"mzeaez", "xcxv", "hjkhk", "azasq", "iopiop"}) {
items.add(createItem(s));
}
System.out.println("Items before sort:");
System.out.println(Item.toString(items));
Collections.sort(items, new ItemComparator());
System.out.println("Items after sort:");
System.out.println(Item.toString(items));
System.out.println("End");
}
private static Item createItem(String s) {
Item item = new Item();
item.setS(s);
return item;
}
}
class Item {
private String s;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
#Override
public String toString() {
return "Item: " + s;
}
public static String toString(Collection<Item> items) {
String s = "";
for(Item item : items) {
s += item + "\n";
}
return s;
}
}
class ItemComparator implements Comparator<Item> {
#Override
public int compare(Item item1, Item item2) {
return item1.getS().compareTo(item2.getS());
}
}

Categories