How to store data from When statement in Drools? - java

I need the data that caused the rule to be fired from the "When" section in the "Then" section of the rule. For instance, if I wanted to make note of all bad apples in a store if there were more than 50, this is how I'm doing it.
Rule "Detect Bad Apples"
When
s : Store( numberOfBadApples() > 50 )
Then
// Print out a list of the bad apples
To make it a little more complicated I have multiple rules that will overwrite. Otherwise, I would store the data into a variable in the Store class.
Is there a better way to do this? I've been reading through the Drools 6.2 Documentation, but I'm still confused.
---EDIT----
The Store Class in Java would look like:
public class Store {
private ArrayList<Apple> appleList;
// The appleList would be filled in another method
public int numberOfBadApples() {
int badAppleCount = 0;
for (Apple apple : appleList) {
if (apple.isBad()) {
badAppleCount++;
}
}
return badAppleCount;
}
}
So in the "Then" statement in Drools, I want to return a list of the apples (the bad ones, in this case) that caused the rule to be fired.

Related

Java class: limit instance variable to one of several possible values, depending on other instance variables

I am sorry for the vague question. I am not sure what I'm looking for here.
I have a Java class, let's call it Bar. In that class is an instance variable, let's call it foo. foo is a String.
foo cannot just have any value. There is a long list of strings, and foo must be one of them.
Then, for each of those strings in the list I would like the possibility to set some extra conditions as to whether that specific foo can belong in that specific type of Bar (depending on other instance variables in that same Bar).
What approach should I take here? Obviously, I could put the list of strings in a static class somewhere and upon calling setFoo(String s) check whether s is in that list. But that would not allow me to check for extra conditions - or I would need to put all that logic for every value of foo in the same method, which would get ugly quickly.
Is the solution to make several hundred classes for every possible value of foo and insert in each the respective (often trivial) logic to determine what types of Bar it fits? That doesn't sound right either.
What approach should I take here?
Here's a more concrete example, to make it more clear what I am looking for. Say there is a Furniture class, with a variable material, which can be lots of things, anything from mahogany to plywood. But there is another variable, upholstery, and you can make furniture containing cotton of plywood but not oak; satin furniture of oak but not walnut; other types of fabric go well with any material; et cetera.
I wouldn't suggest creating multiple classes/templates for such a big use case. This is very opinion based but I'll take a shot at answering as best as I can.
In such a case where your options can be numerous and you want to keep a maintainable code base, the best solution is to separate the values and the logic. I recommend that you store your foo values in a database. At the same time, keep your client code as clean and small as possible. So that it doesn't need to filter through the data to figure out which data is valid. You want to minimize dependency to data in your code. Think of it this way: tomorrow you might need to add a new material to your material list. Do you want to modify all your code for that? Or do you want to just add it to your database and everything magically works? Obviously the latter is a better option. Here is an example on how to design such a system. Of course, this can vary based on your use case or variables but it is a good guideline. The basic rule of thumb is: your code should have as little dependency to data as possible.
Let's say you want to create a Bar which has to have a certain foo. In this case, I would create a database for BARS which contains all the possible Bars. Example:
ID NAME FOO
1 Door 1,4,10
I will also create a database FOOS which contains the details of each foo. For example:
ID NAME PROPERTY1 PROPERTY2 ...
1 Oak Brown Soft
When you create a Bar:
Bar door = new Bar(Bar.DOOR);
in the constructor you would go to the BARS table and query the foos. Then you would query the FOOS table and load all the material and assign them to the field inside your new object.
This way whenever you create a Bar the material can be changed and loaded from DB without changing any code. You can add as many types of Bar as you can and change material properties as you goo. Your client code however doesn't change much.
You might ask why do we create a database for FOOS and refer to it's ids in the BARS table? This way, you can modify the properties of each foo as much as you want. Also you can share foos between Bars and vice versa but you only need to change the db once. cross referencing becomes a breeze. I hope this example explains the idea clearly.
You say:
Is the solution to make several hundred classes for every possible
value of foo and insert in each the respective (often trivial) logic
to determine what types of Bar it fits? That doesn't sound right
either.
Why not have separate classes for each type of Foo? Unless you need to define new types of Foo without changing the code you can model them as plain Java classes. You can go with enums as well but it does not really give you any advantage since you still need to update the enum when adding a new type of Foo.
In any case here is type safe approach that guarantees compile time checking of your rules:
public static interface Material{}
public static interface Upholstery{}
public static class Oak implements Material{}
public static class Plywood implements Material{}
public static class Cotton implements Upholstery{}
public static class Satin implements Upholstery{}
public static class Furniture<M extends Material, U extends Upholstery>{
private M matrerial = null;
private U upholstery = null;
public Furniture(M matrerial, U upholstery){
this.matrerial = matrerial;
this.upholstery = upholstery;
}
public M getMatrerial() {
return matrerial;
}
public U getUpholstery() {
return upholstery;
}
}
public static Furniture<Plywood, Cotton> cottonFurnitureWithPlywood(Plywood plywood, Cotton cotton){
return new Furniture<>(plywood, cotton);
}
public static Furniture<Oak, Satin> satinFurnitureWithOak(Oak oak, Satin satin){
return new Furniture<>(oak, satin);
}
It depends on what you really want to achieve. Creating objects and passing them around will not magically solve your domain-specific problems.
If you cannot think of any real behavior to add to your objects (except the validation), then it might make more sense to just store your data and read them into memory whenever you want. Even treat rules as data.
Here is an example:
public class Furniture {
String name;
Material material;
Upholstery upholstery;
//getters, setters, other behavior
public Furniture(String name, Material m, Upholstery u) {
//Read rule files from memory or disk and do all the checks
//Do not instantiate if validation does not pass
this.name = name;
material = m;
upholstery = u;
}
}
To specify rules, you will then create three plain text files (e.g. using csv format). File 1 will contain valid values for material, file 2 will contain valid values for upholstery, and file 3 will have a matrix format like the following:
upholstery\material plywood mahogany oak
cotton 1 0 1
satin 0 1 0
to check if a material goes with an upholstery or not, just check the corresponding row and column.
Alternatively, if you have lots of data, you can opt for a database system along with an ORM. Rule tables then can be join tables and come with extra nice features a DBMS may provide (like easy checking for duplicate values). The validation table could look something like:
MaterialID UpholsteryID Compatability_Score
plywood cotton 1
oak satin 0
The advantage of using this approach is that you quickly get a working application and you can decide what to do as you add new behavior to your application. And even if it gets way more complex in the future (new rules, new data types, etc) you can use something like the repository pattern to keep your data and business logic decoupled.
Notes about Enums:
Although the solution suggested by #Igwe Kalu solves the specific case described in the question, it is not scalable. What if you want to find what material goes with a given upholstery (the reverse case)? You will need to create another enum which does not add anything meaningful to the program, or add complex logic to your application.
This is a more detailed description of the idea I threw out there in the comment:
Keep Furniture a POJO, i.e., just hold the data, no behavior or rules implemented in it.
Implement the rules in separate classes, something along the lines of:
interface FurnitureRule {
void validate(Furniture furniture) throws FurnitureRuleException;
}
class ValidMaterialRule implements FurnitureRule {
// this you can load in whatever way suitable in your architecture -
// from enums, DB, an XML file, a JSON file, or inject via Spring, etc.
private Set<String> validMaterialNames;
#Overload
void validate(Furniture furniture) throws FurnitureRuleException {
if (!validMaterialNames.contains(furniture.getMaterial()))
throws new FurnitureRuleException("Invalid material " + furniture.getMaterial());
}
}
class UpholsteryRule implements FurnitureRule {
// Again however suitable to implement/config this
private Map<String, Set<String>> validMaterialsPerUpholstery;
#Overload
void validate(Furniture furniture) throws FurnitureRuleException {
Set<String> validMaterialNames = validMaterialsPerUpholstery.get(furniture.getUpholstery();
if (validMaterialNames != null && !validMaterialNames.contains(furniture.getMaterial()))
throws new FurnitureRuleException("Invalid material " + furniture.getMaterial() + " for upholstery " + furniture.getUpholstery());
}
}
// and more complex rules if you need to
Then have some service along the lines of FurnitureManager. It's the "gatekeeper" for all Furniture creation/updates:
class FurnitureManager {
// configure these via e.g. Spring.
private List<FurnitureRule> rules;
public void updateFurniture(Furniture furniture) throws FurnitureRuleException {
rules.forEach(rule -> rule.validate(furniture))
// proceed to persist `furniture` in the database or whatever else you do with a valid piece of furniture.
}
}
material should be of type Enum.
public enum Material {
MAHOGANY,
TEAK,
OAK,
...
}
Furthermore you can have a validator for Furniture that contains the logic which types of Furniture make sense, and then call that validator in every method that can change the material or upholstery variable (typically only your setters).
public class Furniture {
private Material material;
private Upholstery upholstery; //Could also be String depending on your needs of course
public void setMaterial(Material material) {
if (FurnitureValidator.isValidCombination(material, this.upholstery)) {
this.material = material;
}
}
...
private static class FurnitureValidator {
private static boolean isValidCombination(Material material, Upholstery upholstery) {
switch(material) {
case MAHOGANY: return upholstery != Upholstery.COTTON;
break;
//and so on
}
}
}
}
We often are oblivious of the power inherent in enum types. The Java™ Tutorials clearly states "you should use enum types any time you need to represent a fixed set of constants."
How do you simply make the best of enum in resolving the challenge you presented? - Here goes:
public enum Material {
MAHOGANY( "satin", "velvet" ),
PLYWOOD( "leather" ),
// possibly many other materials and their matching fabrics...
OAK( "some other fabric - 0" ),
WALNUT( "some other fabric - 0", "some other fabric - 1" );
private final String[] listOfSuitingFabrics;
Material( String... fabrics ) {
this.listOfSuitingFabrics = fabrics;
}
String[] getListOfSuitingFabrics() {
return Arrays.copyOf( listOfSuitingFabrics );
}
public String toString() {
return name().substring( 0, 1 ) + name().substring( 1 );
}
}
Let's test it:
public class TestMaterial {
for ( Material material : Material.values() ) {
System.out.println( material.toString() + " go well with " + material.getListOfSuitingFabrics() );
}
}
Probably the approach I'd use (because it involves the least amount of code and it's reasonably fast) is to "flatten" the hierarchical logic into a one-dimensional Set of allowed value combinations. Then when setting one of the fields, validate that the proposed new combination is valid. I'd probably just use a Set of concatenated Strings for simplicity. For the example you give above, something like this:
class Furniture {
private String wood;
private String upholstery;
/**
* Set of all acceptable values, with each combination as a String.
* Example value: "plywood:cotton"
*/
private static final Set<String> allowed = new HashSet<>();
/**
* Load allowed values in initializer.
*
* TODO: load allowed values from DB or config file
* instead of hard-wiring.
*/
static {
allowed.add("plywood:cotton");
...
}
public void setWood(String wood) {
if (!allowed.contains(wood + ":" + this.upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.wood = wood;
}
public void setUpholstery(String upholstery) {
if (!allowed.contains(this.wood + ":" + upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.upholstery = upholstery;
}
public void setMaterials(String wood, String upholstery) {
if (!allowed.contains(wood + ":" + upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.wood = wood;
this.upholstery = upholstery;
}
// getters
...
}
The disadvantage of this approach compared to other answers is that there is no compile-time type checking. For example, if you try to set the wood to plywoo instead of plywood you won’t know about your error until runtime. In practice this disadvantage is negligible since presumably the options will be chosen by a user through a UI (or through some other means), so you won’t know what they are until runtime anyway. Plus the big advantage is that the code will never have to be changed so long as you’re willing to maintain a list of allowed combinations externally. As someone with 30 years of development experience, take my word for it that this approach is far more maintainable.
With the above code, you'll need to use setMaterials before using setWood or setUpholstery, since the other field will still be null and therefore not an allowed combination. You can initialize the class's fields with default materials to avoid this if you want.

What is the best way to navigate a complex tree of dissimilar objects?

For example:
class Vehicle {
Collection<Axle> axles;
}
class Axle {
Collection<Wheel> wheels;
}
class Wheel {
// I think there are dually rims that take two tires -- just go with it
Collection<Tire> tires;
}
class Tire {
int width;
int diameter;
}
I have a service through which I can get a collection of all Vehicle objects I know about. Now say I have a tire of a specific width and diameter, and I want to find a Vehicle which can take it. The simplistic way is to have a set of four nested loops, like so:
for (Vehicle vehicle : vehicles) {
for (Axle axle : vehicle.getAxles()) {
for (Wheel wheel : axle.getWheels()) {
for (Tire tire : wheel.getTires()) {
if (tire.width == targetWidth
&& tire.diameter == targetDiameter) {
// do something
break;
}
}
}
}
}
Is there a good design pattern for this? Or a better data structure to use? Would it be better to just keep an index somewhere of tire information mapped to vehicles?
edit: answering questions from comments
Do you have control over the structure of the data you receive from the service?
Yes
Do you need to search for different tires multiple times in the same data?
Yes
Is performance an issue?
Not especially
When you find the tire, do you just need to know which vehicle contains it or do you also need the axle and wheel?
Sometimes just the vehicle, sometimes just the axle -- two different contexts
Do you need the reference to the tire that was found?
Yes, in the cases where I need the axle
edit2:
Extending the metaphor further, to explain the two contexts above:
Context 1 -- I want to know the vehicle, so I can send a worker out to collect the vehicle and bring it back
Context 2 -- I want to know the axle and tire, because I am at the vehicle trying to do the work
You could flatten out the loops by using Java 8 streams.
vehicles.stream()
.flatMap(vehicle -> vehicle.getAxles().stream())
.flatMap(axle -> axle.getWheels().stream())
.flatMap(wheel -> wheel.getTires().stream())
.filter(tire -> tire.width == targetWidth
&& tire.diameter == targetDiameter)
.forEach(tire -> {
// do something
});
The nice thing about streams is that you could insert additional filter, filter, findAny, etc., calls pretty easily anywhere in the sequence.
I would inverse your logic and move the question into the Vehicle, unless of course you'd like to keep your objects thin for any other reason (in which case I'd personally wrap them with a thicker object to add any behaviour needed)
class Vehicle {
...
public Tire acceptsTire(Tire tire) {
}
}
from here on there are several possibilities, depending on how important this piece of business logic is in your domain in general.
If you'll have several actions you could probably just iterate as you had done in your sample. Or possibly in the same way as I suggested, keep cascade the question to the correct component. As long as you can live with the time complexity of doing this that should be alright.
If this check is something you'd usually do then you could have a reference to the type of tires you hold in the vehicle directly, this could be either your Tire collection, or you could pass a TireSpecification instance when constructing the Vehicle if for any reason you need to keep these separated (Your intention is not very clear in the question, is the tire on the car or just an spec of what could fit?)
Without changing your data structure you won't be able to make significant difference. You can add some syntactic sugar with lambdas, but it is essentially the same solution.
Things you could look at:
Your model allows for Vehicles with zero axles or hundred. While it depends on your business model it seems to weird.
Your model allows to have different axles in your vehicle, different wheels. Is it really necessary? Make sure which elements of your model should have their separate identity (currently each object has it) and which is just a value object.
Make sure you really need such detailed model. Currently you have two classes (Axle,Wheel), which only hold collections of inner objects. If they will be just simple JavaBean object with getAllInnerTypes() then you should consider removal of this class. It may even be the case that tire information should be stored almost directly in Vehicle class.
As long as there aren't too many items and/or performance is not a big issue, I would probably just go with the nested loops (or streams from John's answer).
Since you have two contexts for the search, you could pass the appropriate action to the search method - something like this (using loops in this case):
interface TireAction {
void doSomething(Vehicle v, Axle a, Tire t);
}
void findTireAndPerform(int targetWidth, int targetDiameter, TireAction action) {
for (Vehicle vehicle : vehicles) {
for (Axle axle : vehicle.getAxles()) {
for (Wheel wheel : axle.getWheels()) {
for (Tire tire : wheel.getTires()) {
if (tire.width == targetWidth && tire.diameter == targetDiameter) {
action.doSomething(vehicle, axle, tire);
break;
}
}
}
}
}
}
void someMethod() {
...
findTireAndPerform(width, diameter, (v, a, t) -> {
// send worker to 'v'
});
...
findTireAndPerform(width, diameter, (v, a, t) -> {
// work on 'a' and 't'
});
}

java enum string matching

I have an enum as follows:
public enum ServerTask {
HOOK_BEFORE_ALL_TASKS("Execute"),
COPY_MASTER_AND_SNAPSHOT_TO_HISTORY("Copy master db"),
PROCESS_CHECKIN_QUEUE("Process Check-In Queue"),
...
}
I also have a string (lets say string = "Execute") which I would like to make into an instance of the ServerTask enum based on which string in the enum that it matches with. Is there a better way to do this than doing equality checks between the string I want to match and every item in the enum? seems like this would be a lot of if statements since my enum is fairly large
At some level you're going to have to iterate over the entire set of enumerations that you have, and you'll have to compare them to equal - either via a mapping structure (initial population) or through a rudimentary loop.
It's fairly easy to accomplish with a rudimentary loop, so I don't see any reason why you wouldn't want to go this route. The code snippet below assumes the field is named friendlyTask.
public static ServerTask forTaskName(String friendlyTask) {
for (ServerTask serverTask : ServerTask.values()) {
if(serverTask.friendlyTask.equals(friendlyTask)) {
return serverTask;
}
}
return null;
}
The caveat to this approach is that the data won't be stored internally, and depending on how many enums you actually have and how many times you want to invoke this method, it would perform slightly worse than initializing with a map.
However, this approach is the most straightforward. If you find yourself in a position where you have several hundred enums (even more than 20 is a smell to me), consider what it is those enumerations represent and what one should do to break it out a bit more.
Create static reverse lookup map.
public enum ServerTask {
HOOK_BEFORE_ALL_TASKS("Execute"),
COPY_MASTER_AND_SNAPSHOT_TO_HISTORY("Copy master db"),
PROCESS_CHECKIN_QUEUE("Process Check-In Queue"),
...
FINAL_ITEM("Final item");
// For static data always prefer to use Guava's Immutable library
// http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html
static ImmutableMap< String, ServerTask > REVERSE_MAP;
static
{
ImmutableMap.Builder< String, ServerTask > reverseMapBuilder =
ImmutableMap.builder( );
// Build the reverse map by iterating all the values of your enum
for ( ServerTask cur : values() )
{
reverseMapBuilder.put( cur.taskName, cur );
}
REVERSE_MAP = reverseMapBuilder.build( );
}
// Now is the lookup method
public static ServerTask fromTaskName( String friendlyName )
{
// Will return ENUM if friendlyName matches what you stored
// with enum
return REVERSE_MAP.get( friendlyName );
}
}
If you have to get the enum from the String often, then creating a reverse map like Alexander suggests might be worth it.
If you only have to do it once or twice, looping over the values with a single if statement might be your best bet (like Nizil's comment insinuates)
for (ServerTask task : ServerTask.values())
{
//Check here if strings match
}
However there is a way to not iterate over the values at all. If you can ensure that the name of the enum instance and its String value are identical, then you can use:
ServerTask.valueOf("EXECUTE")
which will give you ServerTask.EXECUTE.
Refer this answer for more info.
Having said that, I would not recommend this approach unless you're OK with having instances have the same String representations as their identifiers and yours is a performance critical application which is most often not the case.
You could write a method like this:
static ServerTask getServerTask(String name)
{
switch(name)
{
case "Execute": return HOOK_BEFORE_ALL_TASKS;
case "Copy master db": return COPY_MASTER_AND_SNAPSHOT_TO_HISTORY;
case "Process Check-In Queue": return PROCESS_CHECKIN_QUEUE;
}
}
It's smaller, but not automatic like #Alexander_Pogrebnyak's solution. If the enum changes, you would have to update the switch.

Parsing field access flags in java

I have an assignment wherein I have to parse the field access flags of a java .class file.
The specification for a .class file can be found here: Class File Format (page 26 & 27 have the access flags and hex vals).
This is fine, I can do this no worries.
My issue is that there is a large number of combinations.
I know the public, private and protected are mutually exclusive, which reduces the combinations somewhat. Final and transient are also mutually exclusive. The rest however are not.
At the moment, I have a large switch statement to do the comparison. I read in the hex value of the access flag and then increment a counter, depending on if it is public, private or protected. This works fine, but it seems quite messy to just have every combination listed in a switch statement. i.e. public static, public final, public static final, etc.
I thought of doing modulo on the access flag and the appropriate hex value for public, private or protected, but public is 0x0001, so that won't work.
Does anyone else have any ideas as to how I could reduce the amount of cases in my switch statement?
What is the problem? The specification says that it's a bit flag, that means that you should look at a value as a binary number, and that you can test if a specific value is set by doing a bitwise AND.
E.g
/*
ACC_VOLATILE = 0x0040 = 10000000
ACC_PUBLIC = 0x0001 = 00000001
Public and volatile is= 10000001
*/
publicCount += flag & ACC_PUBLIC > 0 ? 1 : 0;
volatileCount += flag & ACC_VOLATILE > 0 ? 1 : 0;
If you are trying to avoid a pattern like this one I just stole:
if (access_flag & ACC_PUBLIC != 0)
{
public++;
}
if (access_flag & ACC_FINAL != 0)
{
final++;
}
...
It's a great instinct. I make it a rule never to write code that looks redundant like that. Not only is it error-prone and more code in your class, but copy & paste code is really boring to write.
So the big trick is to make this access "Generic" and easy to understand from the calling class--pull out all the repeated crap and just leave "meat", push the complexity to the generic routine.
So an easy way to call a method would be something like this that gives an array of bitfields that contain many bit combinations that need counted and a list of fields that you are interested in (so that you don't waste time testing fields you don't care about):
int[] counts = sumUpBits(arrayOfFlagBitfields, ACC_PUBLIC | ACC_FINAL | ACC_...);
That's really clean, but then how do you access the return fields? I was originally thinking something like this:
System.out.println("Number of public classes="+counts[findBitPosition(ACC_PUBLIC]));
System.out.println("Number of final classes="+counts[findBitPosition(ACC_FINAL)]);
Most of the boilerplate here is gone except the need to change the bitfields to their position. I think two changes might make it better--encapsulate it in a class and use a hash to track positions so that you don't have to convert bitPosition all the time (if you prefer not to use the hash, findBitPosition is at the end).
Let's try a full-fledged class. How should this look from the caller's point of view?
BitSummer bitSums=new BitSummer(arrayOfFlagBitfields, ACC_PUBLIC, ACC_FINAL);
System.out.println("Number of public classes="+bitSums.getCount(ACC_PUBLIC));
System.out.println("Number of final classes="+bitSums.getCount(ACC_FINAL));
That's pretty clean and easy--I really love OO! Now you just use the bitSums to store your values until they are needed (It's less boilerplate than storing them in class variables and more clear than using an array or a collection)
So now to code the class. Note that the constructor uses variable arguments now--less surprise/more conventional and makes more sense for the hash implementation.
By the way, I know this seems like it would be slow and inefficient, but it's probably not bad for most uses--if it is, it can be improved, but this should be much shorter and less redundant than the switch statement (which is really the same as this, just unrolled--however this one uses a hash & autoboxing which will incur an additional penalty).
public class BitSummer {
// sums will store the "sum" as <flag, count>
private final HashMap<Integer, Integer> sums=new HashMap<Integer, Integer>();
// Constructor does all the work, the rest is just an easy lookup.
public BitSummer(int[] arrayOfFlagBitfields, int ... positionsToCount) {
// Loop over each bitfield we want to count
for(int bitfield : arrayOfFlagBitfields) {
// and over each flag to check
for(int flag : positionsToCount) {
// Test to see if we actually should count this bitfield as having the flag set
if((bitfield & flag) != 0) {
sums.put(flag, sums.get(flag) +1); // Increment value
}
}
}
}
// Return the count for a given bit position
public int getCount(int bit) {
return sums.get(bit);
}
}
I didn't test this but I think it's fairly close. I wouldn't use it for processing video packets in realtime or anything, but for most purposes it should be fast enough.
As for maintaining code may look "Long" compared to the original example but if you have more than 5 or 6 fields to check, this will actually be a shorter solution than the chained if statements and significantly less error/prone and more maintainable--also more interesting to write.
If you really feel the need to eliminate the hashtable you could easily replace it with a sparse array with the flag position as the index (for instance the count of a flag 00001000/0x08 would be stored in the fourth array position). This would require a function like this to calculate the bit position for array access (both storing in the array and retrieving)
private int findBitPosition(int flag) {
int ret;
while( ( flag << 1 ) != 0 )
ret++;
return ret;
}
That was fun.
I'm not sure that's what you're looking for, but I would use if-cases with binary AND to check if a flag is set:
if (access_flag & ACC_PUBLIC != 0)
{
// class is public
}
if (access_flag & ACC_FINAL != 0)
{
// class is final
}
....

Java: For loop and If algorithm

I've this question from an assignment to create a Store which rent out books, using a Store.java and Book.java. I've finished this assignment, but I'm curious for better algorithm to a specific part.
--
Book.java
public class Book {
private String name;
Book(String name)
this.name = name;
public String getName()
return name;
}
Store.java
Inside main();
Book bookObj[] = new Book[3]; //Create 3 Array of Object.
bookObj[0] = new Book("Game Over");
bookObj[1] = new Book("Shrek");
bookObj[2] = new Book("Ghost");
Scanner console = new Scanner(System.in)
input = console.nextLine();
Assuming, input = Devil.
Now, I need to do a simple search to check whether the specific book exist.
Example:
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input))
System.out.println("Book Found!");
}
Apparently, this is a for loop that cycles through the array of object and checks whether such Book exist. Now, the problem arise when I want to give an output that the Book was not found.
Example:
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input))
System.out.println("Book Found!");
else
System.out.println("Book not Found!");
}
The problem with the above code is that Book not Found would be printed thrice. My goal is to avoid such problem. I do have solutions to this, but I'm still in search for a better one to use that utilizes getName(), which in my opinion still has room to improve.
Usually, in structural programming, I would do the following,
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input))
System.out.println("Book Found!");
else if(i == bookObj.length - 1)
System.out.println("Book not Found!");
}
This is useful to tell whether it's the end of the loop, and the search has ended, but there was no successful result from the search.
How should I think of it in Object Oriented way?
All in all, my question is,
Is there a better way to write the above code rather than checking that it's the end of the line?
Is there a better way to utilize getName() method or to use other methods?
You should loop through the array and use an index / boolean flag to store whether or not the book is found. Then print the message in the end, based on the index / flag value.
int foundAtIndex = -1;
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input)) {
foundAtIndex = i; // store the actual index for later use
break; // no need to search further
}
}
if(foundAtIndex >= 0)
System.out.println("Book Found!");
else
System.out.println("Book not Found!");
Alternatively (unless your assignment specifically requires using an array) you should prefer a Set, which can do the search for you with a single call to contains().
How should I think of it in Object Oriented way?
When looking at a single method, there is not much difference between procedural and OO style. The differences start to appear at a higher level, when trying to organize a bunch of conceptually related data and methods that operate on these.
The OO paradigm is to tie the methods to the data they operate on, and encapsulate both into coherent objects and classes. These classes are preferably representations of important domain concepts. So for your book store, you may want to put all book related code into your Book class. However, the above search method (and the collection of books it operates on) is not related to any particular book instance, so you have different choices:
put both the collection of books and the search method into Store (probably as regular members), or
put them into Book as static members.
The first choice is more natural, so I normally would prefer that. However, under specific circumstances the second option might be preferable. In (OO) design, there are hardly ever clean "yes/no" answers - rather tradeoffs between different options, each having their own strengths and weaknesses.
You could introduce state and remember whether you have found the book or not.
If you're not using Java 1.4 or earlier, you could also use the foreach loop syntax:
boolean bookFound = false;
for(Book currentBook : bookObj) {
if(currentBook.getName().equals(input))
//TODO: see above
}
Also, I would suggest looking into the Collections library, and replace your array with a list or set:
Set<Book> books = new HashSet<Book>();
books.put(new Book("Game Over"));
books.put(new Book("Shrek"));
books.put(new Book("Ghost"));
And, while were at it, you could also think about when two books are equal and override equals() and hashCode() accordingly. If equal() would be changed to check the title, you could simply use books.contains(new Book(input)); and have the libraries do the work for you.
To solve the problem in a better way you must understand that the power of Java comes not from the language itself but from the Java Framework.
You should learn the usage of the Java Collection classes (never work with arrays anymore). Then you will be able to solve the search with just one line of code:
ArrayList<Book> listOfBooks;
// init your list here
listOfBooks.contains(new Book(input));
To make this work, you must also learn how to correctly implement the equals() method of your Book class.
Happy learning!
Here is a working solution :
import java.util.Scanner;
public class Store {
private static class Book {
private String name;
Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static void main(String[] args) {
String input;
Book[] bookObj = new Book[3];
bookObj[0] = new Book("Game Over");
bookObj[1] = new Book("Shrek");
bookObj[2] = new Book("Ghost");
Scanner console = new Scanner(System.in);
input = console.nextLine();
boolean found = false;
int i = 0;
while(!found && i < bookObj.length) {
if(bookObj[i].getName().equals(input)) {
System.out.println("Book Found at position : " + i);
found = true;
} else {
i++;
}
}
if(!found) {
System.out.println("Book not Found!");
}
// Here i contains the indice of the element found in the array.
}
}
You've gotten some pretty good advice thus far. You asked if there was a more Object Oriented way of thinking about the problem so I thought I'd try and shed some light on it. As Peter already mentioned at this level of the design it's a single method implementation so the approach is going to be fairly similar as say a procedural approach. What's the advantage? In a word reuse. If you needed to find a book by name in lots of places then moving the code to it's own class will help.
So what you have is a single Book instance to encapsulate behavior around a single book, but you want to have behavior about multiple books, or a collection of books. You can keep the data (array of books), and the method that account on them separate as you outlined in your program. However, if we wanted to collect a place for doing behavior on a collection of books we can define a new class. Let's call it Library, and we might do something like the following:
public class Library {
private Book[] books;
private bookCount = 0;
public Library( int numberOfTotalBooks ) {
books = new Book[numberOfTotalBooks];
}
public boolean addBook( Book book ) {
if( bookCount < book.length ) {
books[bookCount++] = book;
return true;
}
return false;
}
public Book findByTitle( String title ) {
for( int i = 0; i < bookCount; i++ ) {
if( books[i].getTitle().equals( title ) ) {
return books[i];
}
}
// didn't find one
return null;
}
}
So a couple of things to note about doing things this way. One is that when we work with a Library we don't know there is an Array back there. We could use an array, a Set, a List, or a database (most common). The point being the code that calls these functions just works with the interface of Library (not a literal Java interface, but the method signature of Library). Also this is a higher level interface. We don't worry about iterating over the books, doing for loops, if statements, etc. We just call a method saying "Hey find this book title in the Library". How that's done we don't care. This is the basic tenant of Object Orientation called encapsulation, and it's deceptively powerful. It's really about how we delegate responsibility in our program, and give the details of a job to individual class or classes. If Library had only public members (i.e. books and bookCount), or getter/setters then the client wouldn't be getting any advantages because the client would still have to do all the heavy lifting. The trick to OO is figuring out what can be delegated out of an object, without creating problems. This takes practice, and experience.
The second thing here is we've separated the presentation from the act of finding a book. The method you wrote assumed the next step which was to print "Hey we found it." However, Library object simply returns the Book to you when it finds it, or null if it didn't. That makes it possible to print to the console, display in a GUI, or serialize it to a JSON stream in a server. The act of finding a book is separate from the visualization. This is another important aspect of programming in general, but some what related to object orientation and encapsulation. This is typically called separation of concerns. The console application has concerns about supporting the UI, and printing the console. While the Library just manages cataloging and managing the book collection. How those details are performed neither cares.
In the end Library is a reusable class. We can use it in a console application, desktop, web, or middleware server. More importantly is we can also reuse the calls to findByTitle or addBooks from multiple locations within a single program. Also by putting the methods with the data we create a barrier to where that function can be used. You can't do it anywhere in your program. You have to have a reference to Library. If you don't have reference to a Library instance then you shouldn't be calling it. This can be troublesome to new developers because they lack the experience to properly organize their programs to not get into trouble with this (then they start doing value objects, creating statics, singletons, etc and things turn into a big ball of mud). It's a double edged sword.
One more thing I'd like to point out is say we wanted to model two Libraries. We have a Library uptown and downtown, and we want to allow people to check out books from either Library. With OO that's really easy to represent:
Library uptown = new Library( 50 );
Library downtown = new Library( 100 );
Now we can check out books from one or the other. And I didn't use statics (i.e. global variables) so reusing that logic is really easy. These are the basics of OO so they are really deep topics. Strange how I can write so much on very simple topics. Anyway I hope this helped you understand your program a little deeper, and see how you can use OO to help you.
chubbsondubs came closest to giving a correct answer to this question
What he missed is that his algorithm is incorrect because it contains two tests, when only one is needed. The correct code requires only 3 statements and is as follows:
public boolean zLibaryContains( String title ) {
books[bookCount] = title;
int xBook = 0;
while( true )
if( books[xBook].getTitle().equals( title ) )
return xBook != bookCount;
else xBook++;
}
Noticeably smaller and faster than all other solutions. Simplify, simplify, simplify.
Object-oriented code is a crutch to support poor designs that would otherwise be too complex to understand. The goal is write code that is so easy to understand and maintain that OO is unnecessary and would make the program worse. When your program can be improved by adding OO, it means you are doing something wrong to begin with.

Categories