the question is the same as in the title. i have arraylist to which i add incomes or expenses both in form of a object. will this loop sum up all elements, and is there a better way of doing this :?
public void sumOfAllExpAndIn(){
int tmp = 0;
for (Iterator<Object> it = database.iterator(); it.hasNext();){
if (it.next() instanceof Expenses){
Expenses excalc = new Expenses();
excalc = (Expenses) it.next();
tmp -= excalc.value;
}
else {
incomes incalc =new incomes();
incalc = (incomes) it.next();
tmp += incalc.value;
}
}
System.out.format("the overall balance is %d",tmp);
}
Yes there are several better ways of doing it.
Firstly, I don't suggest you declare it as an Object list. Better is to declare an interface and then implement the interface in each of your classes:
interface BudgetValue {
double getValue();
}
class Expense implements BudgetValue {
public double getValue() {
return -value;
}
}
class Income implements BudgetValue {
public double getValue() {
return +value;
}
}
Then you can declare list of BudgetValues rather than Objects as the input to your method:
double sumBudgetValues(List<BudgetValues> budgetValues) {
}
There are two easy ways of summing them:
double total = 0.0;
for (BudgetValue value: budgetValues) {
total += value.getValue();
}
return total;
or using Java 8:
return budgetValues.stream()
.mapToDouble(BudgetValue::getValue)
.sum().orElse(0.0);
The streams method makes a lot more sense to me and allows it to be easily multithreaded if you have a lot of values to sum by turning it into a parallel stream.
There are some rare occassions where instanceof is justified but, as a rule of thumb, if you find yourself using it then start by asking yourself whether there's an interface missing.
I suggest making your Expenses and Incomes classes implement a common interface, for example LineItem. Now if you use signed values (positive for incomes and negatives for expenses), you only have to call getValue() on any implementation of LineItem and add it to your running total... no if/else needed, no collection of Object needed.
public void sumOfAllExpAndIn(){
int tmp = 0;
for (Iterator<LineItem> it = database.iterator(); it.hasNext();){
tmp += it.next().getValue();
}
}
System.out.format("the overall balance is %d",tmp);
}
Related
I am learning usage of,
java.util.function.Function
I wrote a code which uses java Function to add 4 to itself,
the code is as follows,
public class Test01 {
public static void main(String[] args) {
Function<Integer,Integer> addFunction = new Function<Integer,Integer>() {
private int total = 0;
public Integer apply(Integer value) {
this.total += value;
return this.total;
}
};
int finalTotal = addFunction.andThen(addFunction)
.andThen(addFunction)
.andThen(addFunction)
.apply(4);
System.out.println(finalTotal);
}
}
When I run the above code the output which I get is
32
How can I achieve something which I did in javaScript which is as follows,
var fn19 = function(){
var addNum = function(num){
var fn = function(num2){
fn.sum += num2;
return fn;
};
fn.sum = num;
return fn;
};
print("addNum(3)(4)(3)(10) ==> "+addNum(3)(4)(3)(10).sum);
};
fn19();
The output of the above code is
addNum(3)(4)(3)(10) ==> 20
Can I have the same kind of java function call where I can pass as many number arguments and the addFunction will add those many numbers.
An example, as close as possible to your JavaScript code, would be
class QuestionableConstruct {
int sum;
QuestionableConstruct add(int num2) {
sum += num2;
return this;
}
}
Runnable fn19 = () -> {
IntFunction<QuestionableConstruct> addNum = num -> {
QuestionableConstruct fn = new QuestionableConstruct();
fn.sum = num;
return fn;
};
System.out.println("addNum(3)(4)(3)(10)==> "+addNum.apply(3).add(4).add(3).add(10).sum);
};
fn19.run();
A more Java like solution would be
interface Add {
int sum();
default Add add(int num) {
int sum = sum() + num;
return () -> sum;
}
static Add num(int num) {
return () -> num;
}
}
usable as
System.out.println("addNum(3)(4)(3)(10) ==> "+Add.num(3).add(4).add(3).add(10).sum());
Unlike the JavaScript construct, this uses real immutable functions. Consider
Add a = Add.num(1).add(2).add(3);
System.out.println("1+2+3+4+5 = "+a.add(4).add(5).sum());
System.out.println("1+2+3+10+20 = "+a.add(10).add(20).sum());
which works smoothly without interference.
But of course, if you just want to sum a variable number of items, use
System.out.println("addNum(3)(4)(3)(10) ==> "+IntStream.of(3, 4, 3, 10).sum());
or if you want a mutable accumulator, use
System.out.println("addNum(3)(4)(3)(10) ==> "+
IntStream.builder().add(3).add(4).add(3).add(10).build().sum());
which allows to keep the builder and pass it around.
You can't exactly do that in Java, what you are looking for is reducing a stream of values.
In other words: the "real" functional solution here isn't to call one method with multiple arguments. You rather have the values in some list, and then you define the function that "accumulates" over the content of that list, by applying a function on the elements.
See here for some examples.
The technique you're describing in the JavaScript world is taking advantage of a closure.
This is a nice side-effect of functions in JavaScript being first-class citizens. It's a way of associating functions with data in the enclosing scope and then being able to pass this association around without losing inner context. The most common/simple use of which is caching(its formal name being memoisation).
You would need functions(methods) in Java to be first class, but doing so would be redundant as classes by design are an entity which associates data and methods, making the whole concept of a closure in this context redundant.
Let's say I have a class Item like this:
class Item {
private long id;
private BigDecimal value1;
private BigDecimal value2;
private BigDecimal value3;
}
Then I have a list with many itens, I want to know the sum of each of the values:
So, I know I could do something like
BigDecimal v1 = list.stream().map(Item::value1).reduce(BigDecimal.ZERO, BigDecimal::add);
However, this way I would need to do the same for each value, I'd like to know if there's some way of summing each attribute into only one Dto like:
class TotalItem {
private BigDecimal value1;
private BigDecimal value2;
private BigDecimal value3;
}
TotalItem t = list.stream().map(???).reduce(BigDecimal.ZERO, BigDecimal::add);
Is this possible?
thanks in advance.
I didn't test it but I think that you can implement add function on Item like:
public Item add(Item other) {
Item newItem = new Item(this.value1 + other.value1,
this.value2 + other.value2,
this.value3 + other.value3);
return newItem;
}
and then do:
Item t = list.stream().reduce(BigDecimal.ZERO, Item::add);
How about the following way?
TotalItem t = new TotalItem();
list.stream().forEach(item -> {
t.value1+ = item.value1;
t.value2+ = item.value2;
t.value3+ = item.value3;
});
I'm making the assumption that Item/TotalItem are very large objects, which would make writing a toTotalItem and a summarise(TotalItem,TotalItem) by hand a large and laborious job. One that is completely boilerplate and easy to get wrong.
Change the data structure to be a list or map - This makes summarisation simpler, at the cost of readability of the code and type safety.
Use reflection to iterate over the fields.
TotalItem toTotalItem(Item item) {
Field[] targetFields = TotalItem.class.getFields();
Collection<Field> sourceFields = Item.class.getFields().stream()
.filter(x=>fieldNameIsIn(x, targetFields)
.collect(Collectors.toList());
TotalItem returnItem = new TotalItem();
for(Field field : sourceFields) {
toTargetField(field, targetFields).set(returnItem, (BigDecimal) field.get(item));
}
return returnItem;
}
boolean fieldNameIsIn(Field sourceField, Field[] targetFields) // exercise for the reader
Field toTargetField(Field sourceField, Field[] targetFields) // exercise for the reader
This code above is not neat, but should show the concept. The same concept could be used to summarise.
This reduces the amount of code you need to write, but at the cost of runtime speed. Reflection is also hard to get right and magic (which some developers do not like).
The faster option would be a custom annotation which adds in summarisation. However this would be large chunk of work. If you have a large number of objects that need this, then it may make sense. Like reflection it is hard to get right and magic (which some developers do not like). Luckily you do not need a build step as Javac supports annotation processing natively.
This answer is inspired by JDK way of doing similar operations. Namely, I'll be referencing DoubleSummaryStatistics class.
First, we define a holder for information about BigDecimals we'll be collecting:
public class BigDecimalSummaryStats {
private long count;
private MathContext mc;
private BigDecimal sum = BigDecimal.ZERO;
private BigDecimal max;
private BigDecimal min;
public BigDecimalSummaryStats(MathContext mathCtx) {
mc = requireNonNull(mathCtx);
}
public Supplier<BigDecimalSummaryStats> supplier(MathContext ctx) {
return () -> new BigDecimalSummaryStats(ctx);
}
public void accept(BigDecimal value) {
requireNonNull(value);
count++;
sum = sum.add(value, mc);
min = min.min(value);
max = max.max(value);
}
public void combine(BigDecimalSummaryStats other) {
requireNonNull(other);
count += other.count;
sum = sum.add(other.sum, mc);
min = min.min(other.min);
max = max.max(other.max);
}
public long getCount() {
return count;
}
public BigDecimal getSum() {
return sum;
}
public BigDecimal getMax() {
return max;
}
public BigDecimal getMin() {
return min;
}
public BigDecimal getAverage() {
long c = getCount();
return c == 0 ? BigDecimal.ZERO : getSum().divide(BigDecimal.valueOf(c), mc);
}
}
This will provide with nice general utility suitable for collecting summary from arbitrary sequences of BigDecimal values.
Then, we can define a Summary class for our Item:
public class ItemSummaryStats {
private BigDecimalSummaryStats value1;
private BigDecimalSummaryStats value2;
private BigDecimalSummaryStats value3;
// ... other fields as needed
public ItemSummaryStats(MathContext math) {
value1 = new BigDecimalSummaryStats(math);
value2 = new BigDecimalSummaryStats(math);
value3 = new BigDecimalSummaryStats(math);
}
public void accept(Item item) {
value1.accept(item.value1);
value2.accept(item.value2);
value3.accept(item.value3);
// ... other fields as needed
}
public void combine(ItemSummaryStats other) {
value1.combine(other.value1);
value2.combine(other.value2);
value3.combine(other.value3);
}
public TotalItem get(
Function<BigDecimalSummaryStats, BigDecimal> v1Mapper,
Function<BigDecimalSummaryStats, BigDecimal> v2Mapper,
Function<BigDecimalSummaryStats, BigDecimal> v3Mapper) {
TotalItem t = new TotalItem();
t.value1 = v1Mapper.get(value1);
t.value2 = v2Mapper.get(value2);
t.value3 = v3Mapper.get(value3);
return t;
}
public TotalItem getSum() {
return get(BigDecimalSummaryStats::getSum,
BigDecimalSummaryStats::getSum,
BigDecimalSummaryStats::getSum);
}
public TotalItem getAverage() {
return get(BigDecimalSummaryStats::getAverage,
BigDecimalSummaryStats::getAverage,
BigDecimalSummaryStats::getAverage);
}
public TotalItem getMin() {
return get(BigDecimalSummaryStats::getMin,
BigDecimalSummaryStats::getMin,
BigDecimalSummaryStats::getMin);
}
//.... other methods basically all the same. You get the idea.
}
And finally we use this goodness like this:
TotalItem totals = list.stream().collect(
Collector.of(() -> new ItemStatsSummary(MathContext.DECIMAL64),
ItemStatsSummary::accept,
ItemStatsSummary::combine,
ItemStatsSummary::getSum)
)
Cons of this approach:
Slightly longer development time than adhoc solutions.
Are far outweighed by the pros, or at least I'm convinced of it:
Follows separation of concerns principle: Item Stats are not actually concerned how to collect summary of specific field: they can trust that BigDecimalSummary works
Testable: Each part can be tested in its own suite. You can trust that every field will work the same since they use the same API.
Flexible: get(Function...) method exposes a big list of possibilities: you can collect sum of first field, an averabe of second and min of third if needed.
Java beginner here. I'm supposed to find the best result a participant has in an event (and later compare this result to others to find the winner etc).
I made classes for an event (with list of event results) , participant (with list of participant's total results), and result (with event obj, participant obj and result (double)) + a program class for the commands.
So far I have written a method that returns a participant's best result in an event as a double, but I need to return the entire result object instead. Not sure which class should be responsible for this (?) but I put this method in the event class for now.
public double getBestResultDouble(Participant p) {
double best = 0;
if (hasResult(p)) {
for (Result r : eventResults) {
if (p.equals(r.getParticipant())) {
double res = r.getResult();
if (res > best) {
best = res;
}
}
}
}
return best;
}
Simply save the corresponding (best) result as another local variable and return that at the end:
public Result getBestResultDouble(Participant p) {
double best = 0;
Result bestResult = null;
if (hasResult(p)) {
for (Result r : eventResults) {
if (p.equals(r.getParticipant())) {
double res = r.getResult();
if (res > best) {
best = res;
bestResult = r;
}
}
}
}
return bestResult;
}
Try to think a little more in terms of OOP (Object-Oriented Programming).
A Participant can participate in multiple Event's. Everytime a Participant participates in an Event, there is a Result that gets generated for that particular Participant and gets a corresponding score.
Now that I have the basic structure of how I want to layout my classes, so we can define specific behavior of how we want each class to go about.
public class Participant
{
private List<Event> events;
private String name;
public Participant( String name )
{
this.name = name;
events = new ArrayList<Event>();
}
//... other methods
public void participate( Event event )
{
double score;
//... get the score
events.add( event );
event.recordResult( this, score );
}
}
So now the Participant can participate in certain Event's that you define.
Now looking at what I did in that participate method, we need to have a way to store Result's inside of an Event.
public class Event
{
private List<Result> results;
public Event()
{
results = new ArrayList<Result>();
}
// ...
public void scoreResult( Participant participant, double score )
{
//if a participant cannot participate multiple times in an event, probably need a check to see if
//the participant is already in the list, otherwise update the score isntead of adding a new Result
results.add( new Result( participant, score ) );
}
}
So now each Event that you define has a way to score a Result for a particular Participant.
I'll just do the basic outline for a Result class
public class Result
{
private Participant participant;
private double score;
public Result( Participant participant, double score )
{
this.participant = participant;
this.score = score;
}
// ... getters and setters
}
This could be a basic outline for your Objects. Now you can define a method in Participant to get the best Result of all Event's he has participated in. Something like:
public Result getBestResult()
{
Result bestResult = null;
for( Event event : events )
{
if( bestResult == null )
bestResult = event.getResult();
if( bestResult.getScore() < event.getResult().getScore() )
bestResult = event.getResult();
}
//if the participant hasn't participated in any event, then this will return a null result.
return bestResult;
}
I hope that this makes sense and will help you think about things in a more OO way. This way you can define other methods for Event such as how to get the Participant with the highest Result.
Of course this is just one way to layout the classes, and I highly encourage you to try to think ahead of time how you want your objects to interact with each other before coding. Think about relationships between objects. I know you are just a beginner, so this might be a little advanced, but if you are serious about learning how to code efficiently, this is definitely something to look into.
In Java, the most common way is to create an instance of Comparator<Result>, which compares instances of Result. You delegate the comparison to the Comparator instead of comparing yourself.
You can then use standard Java methods to do your sorting.
Standard:
List<Result> = ....
Comparator<Result> cmp = ....;
list.sort(cmp);
Result max = list.get(0);
With Streams
List<Result> = ....
Comparator<Result> cmp = ....;
Result max = list.stream().max(cmp);
Double is already Comparable, so you can code your Comparator like:
Comparator<Result> cmp = new Comparator() {
public int compare(Result r1, Result r2)
{
return r1.getResult().compareTo(r2.getResult());
}
}
This code works perfectly, but unfortunately it triggers garbage collection because of the Arrays.sort() Comparator.
Is there a way to do this that won't trigger Garbage Collection?
(NOTE: This code has been modified to be more "generic". The actual code is for an Android game, which is why Garbage Collection-induced slowdown is an issue.)
static final byte INCOME = 0;
static final byte INDEX = 1;
public void vSortEmployees() {
nPaidEmployees = 0;
for (nIter=0; nIter<MAX_EMPLOYEES; nIter++) {
if ((employees[nIter].current == true) && (employees[nIter].volunteer == false)) {
// We have another current and paid employee; add that employee's "amount earned to date" to the list.
paidemployees[nPaidEmployees][INCOME] = employees[nIter].fGetTotalIncomeToDate();
paidemployees[nPaidEmployees][INDEX] = nIter;
nPaidEmployees++;
}
}
Arrays.sort(paidemployees, new Comparator<float[]>() {
#Override
public int compare(float[] f1, float[] f2) {
if (f2[INCOME] < f1[INCOME])
return -1;
else if (f2[INCOME] > f1[INCOME])
return 1;
else
return 0;
}
});
// Now we have a list of current, paid employees in order of income received.
// Highest income paid out
paidemployees[0][INCOME]
// Second highest income paid out
paidemployees[1][INCOME]
// If we need to reference the original employee object, we can:
employees[paidemployees[0][INDEX]].getName();
}
There is not way to consistently trigger or not to trigger GC. GC lives its own life. The fact that it runs when you are sorting your array does not mean anything.
But however you probably can do something. Just do not user anonymous inner class for comparator. You do not really need this. Use regular class and create its object as a singleton. Then just use this instance. In this case no new objects will be created in your code during the sort and GC probably will not run.
class FloatArrayComparator implements Comparator<float[]>() {
#Override
public int compare(float[] f1, float[] f2) {
if (f2[INCOME] < f1[INCOME])
return -1;
else if (f2[INCOME] > f1[INCOME])
return 1;
else
return 0;
}
};
class SomeClass {
private Comparator<float[]> floatArrayComparator = new FloatArrayComparator();
void myMethod() {
Arrays.sort(myArray, floatArrayComparator);
}
}
public class OrderProcessor {
public Double calculateTotalPriceWithDiscountCode(Order order,
char discountCode) {
Double itemTotal = order.getItemTotal();
Double discountAmount = 0.0;
switch (discountCode) {
case 'A':
discountAmount = 0.95 * itemTotal;
break;
case 'B':
discountAmount = 0.15 * itemTotal;
break;
}
return itemTotal - discountAmount;
}
Current implementation in order processor is closed for extension and open for modification for adding new discount codes, how can i improve the design to get rid of this limitation
In general, the presence of a switch is a pretty good giveaway as to what should be a class instead. So, a first stab at it would be something like this:
public interface Discounter {
public double applyDiscount(double itemTotal);
}
public class OrderProcessor {
private Map<Char, Discounter> discounts = new HashMap<Char, Discounter>();
public void addDiscounter(Char discountCode, Discounter discounter) {
discounts.put(discountCode, discounter);
}
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
double itemTotal = order.getItemTotal();
double discountAmount = 0.0;
if (discounts.hasKey(discountCode))
discountAmount = discounter.applyDiscount(itemTotal);
return itemTotal - discountAmount;
}
}
This would then be extended through something like this:
processor.addDiscounter('A', new Discounter() {
public double applyDiscount(double itemTotal) {
return 0.95 * itemTotal;
}
});
You could make a remove method as well, and then your discounters can become more complex, consulting external data, etc. You may want to open up the interface a bit and pass in the whole order for more examination.
Note: If this is something you're going to be doing in production I have two pieces of unsolicited advice:
Consider using something like JBoss Drools to handle your business logic instead of this; it's a lot more powerful and flexible.
Please don't use double for actual financial calculations. :)
As you have pointed out that the discount code needs to be changeable, it is best to separate out the actual discount codes from the code. Maintain the discount codes in an xml or settings file and lazy load the values into a dictionary/hashset before using them.
For example your xml could look like this,
<Discounts>
<Discount code="A" value="0.05"/>
<Discount code="B" value="0.10"/>
<Discount code="C" value="0.15"/>
</Discounts>
In your calculateTotalPriceWithDiscountCode, populate a dictionary with the values read from this xml.
if(discountsDictionary == null)
{
discountsDictionary = LoadValuesFromXml(xmlFilePath);
}
In case your discounts xml is likely to change during program execution then perform the Load operation when you want the discount value (as compared to loading once in the above code fragment).
Then access the code (key) to retrieve the discount (value),
if(discountsDictionary.ContainsKey(discountCode))
{
discount = discountsDictionary[discountCode];
discountedItemPrice = itemPrice * ( 1 - discount);
}
else
{
// Invalid discount code...
}
Pull the logic for calculating totals based on an order into its own class/interface:
class OrderProcessor {
// Probably inject this or load it some other way than a static factory
private Collection<TotalCalculator> calculators = TotalCalculatorFactory.getTotalCalculators();
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
for (TotalCalculator calculator : calculators) {
if (calculator.supports(discountCode)) {
return calculator.calculateTotal(order);
}
}
return order.getItemTotal();
}
}
class TotalCalculator {
private char discountCode;
private double discountRatio;
public TotalCalculator(char discountCode, double discountRatio) {
this.discountCode = discountCode;
this.discountRatio = discountRatio;
}
public boolean supports(char discountCode) {
return this.discountCode == discountCode;
}
public Double calculateTotal(Order order) {
return order.getItemTotal() - order.getItemTotal() * discountRatio;
}
}
class TotalCalculatorFactory {
public static Collection<TotalCalculator> getTotalCalculators() {
return Arrays.asList(
new TotalCalculator('A', 0.95),
new TotalCalculator('B', 0.15)
);
}
}
In a real system, I'd make the TotalCalculator an interface, which would have the additional advantage of being able to calculate order totals in other ways than just a percentage discount reduction.
This solution is also very flexible in allowing you to create your TotalCalculators (or implementations if an interface) using other mechanisms than manually coding them into a factory. You can use an IoC container to create and inject them or use a ServiceLoader to find and load them, for example.
My idea is maintain discounts separately.
public class OrderProcessor {
public Double calculateTotalPriceWithDiscountCode(Order order,
char discountCode) {
Double itemTotal = order.getItemTotal();
return itemTotal - (itemTotal* Discounts.GetDiscounts(discountCode));
}
}
////////////////
class Discounts
{
public static double GetDiscounts(char discountCode)
{
switch (discountCode) {
case 'A':
return 0.95d;
case 'B':
return 0.15d;
default:
return 0.00d;
}
}
}
In this calculateTotalPriceWithDiscountCode function, it is not a good idea to pass a discount code as parameter. Well, 3rd person , who review your code , would not understand would not understand what does it mean except you, a kind of code smell.
One of a suggestion is that you need to create another class called Discount, and you pass the Discount object as a parameter, and you get the internal value from its public method.
i.e.
public class Discount {
//Use a hash map to store your Code associate with your discountAmount
public Discount(char discountCode){
this.discountCode = discountCode
}
public int getDiscountAmount(){
....
....
}
}
Right now, what you actually need to modify will be the Discount Class only, and your calculateTotalPriceWithDiscountCode will not need to care.
You could use a separate xml file for storing codes as well as their calculation mechanishms.
This will remove the limitation of inablility to add new discount code.
XML File: discounts.xml
<discount-codes>
<discount-code>
<code>A</code>
<val>0.15</val>
</discount-code>
<discount-code>
<code>B</code>
<val>0.95</val>
</discount-code>
</discount-codes>
Note: Operation code (What am I intended to do with the values?) is not currently implemented. You can implement the same at your end.
Use an XML parser class:
Class: DiscountModel.java (This class is the model to store the discount codes)
public class DiscountModel {
char code;
Double val;
// Implement getters and setters
}
Class: DiscountParser.java (This will parse the discounts.xml file and store the codes in a list)
public class DiscountParser {
List<DiscountModel> discountsList;
// Getters and Setters for discountsList
// Parser Code
public void parseDiscounts() {
// Code here
}
// Add new discount
public void addDiscount() {
// Code
}
// Remove discount
public void removeDiscount () {
// Code
}
}
Class: OrderProcessor.java (This will bring out the discounted value after calculation)
/**
* Call this class when calculations need to be done.
*/
public class OrderProcessor {
// Declare instance of DocumentParser
DocumentParser dc1;
// Getter and setter for dc1
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
// Find the corresponding discountcode and
// value from the list of values in the
// Class DocumentParser
// Use the corresponding values to calculate
// the discount and return the value
}
}
Whenever a new code is to be added, you can insert the same to the xml file. The same applies if the discount code needs to be removed.
Hope the above helps.