I have an application where I need to handle a lot of numbers (Integers or Longs) comming from external sources.
The numbers can be null. In case they are null I always need to convert them to 0.
The problem seems trivial, but I don't want to write hundreds of times:
if (someNumber == null) {
someNumber = 0;
}
I don't like it for two reasons:
I don't like to write three lines of code for such simple task, especially because I need to do it many times
I don't like to to "mutate" someNumber (assign new value to someNumber variable)
I tried some other ways which can be seen here:
public static void main(String[] args) {
Integer zeroOrNull = new Random().nextBoolean() ? 0 : null;
// version1: this is nasty (I already mentioned why)
if (zeroOrNull == null) {
zeroOrNull = 0;
}
// version2: this seems to much for so simple task...
zeroOrNull = Optional.ofNullable(zeroOrNull).orElseGet(() -> 0);
// version3: creating an util might be considerable. Is there already such predefined util ?
zeroOrNull = MyUtil.getValueOrZero(zeroOrNull); // returns value or )
System.out.println(zeroOrNull); // I want 0 here in case of null
}
What is the preffered and nice way to do such "test for null/conversion to 0" ? Any chance to do this conversion implicitly?
Use i = (i==null)?0:i;
one line check
no method call
plain and simple
no additional dependency (unlike some other proposed solutions)
Place this check as close to your numbers source as possible, to avoid unnecessary duplications.
By creating overloaded versions of Null Checker
public static void main(String args[]) {
Integer intObj = null;
System.out.println("intObj : " + checkNull(intObj));
intObj = 1122222;
System.out.println("intObj : " + checkNull(intObj));
Long longObj = null;
System.out.println("longObj : " + checkNull(longObj));
longObj = 666555556L;
System.out.println("longObj : " + checkNull(longObj));
System.out.println("*********With default value***********");
intObj = null;
System.out.println("intObj : " + checkNull(intObj, 1));
intObj = 1122222;
System.out.println("intObj : " + checkNull(intObj, 1));
longObj = null;
System.out.println("longObj : " + checkNull(longObj, 0L));
longObj = 666555556L;
System.out.println("longObj : " + checkNull(longObj, 0L));
}
static Integer checkNull(Integer obj) {
if (obj == null)
return 0;
return obj;
}
static Long checkNull(Long obj) {
if (obj == null)
return 0L;
return obj;
}
static Integer checkNull(Integer obj, int i) {
if (obj == null)
return i;
return obj;
}
static Long checkNull(Long obj, long l) {
if (obj == null)
return l;
return obj;
}
A simple solution would be to write a utility method like below:
public static Integer checkNullNumber(Integer i){
if(i == null)
return 0;
return i;
}
Now you can use this method wherever you want like:
zeroOrNull = checkNullNumber(zeroOrNull);
I don't like to write three lines of code for such simple task,
especially because I need to do it many times
if (zeroOrNull == null) zeroOrNull = 0;
I don't like to to "mutate" someNumber (assign new value to someNumber
variable)
there is no way to change the null-value into a "0" without constructing a new Integer object that holds this "0" and this single line of code does just that
Use java8 java.util.Optional class is very efficient, but don't use
explicit null values, use empty Optional
This is my original answer, if "efficient" was intended only by "performance" I've wronged word, sorry.
The mean is that all coding process is better, develop and execution are more safe.
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
Related
I have a Object which contains a list of another object which contains a list of another object and so on... suppose I want to get count of nested list elements(lets say last one), what should be best approach rather than using traditional for loop in java as I have done in below example -
public static void main(String[] args) {
Statement statement = new Statement();
statement.getInvAccount().add(new InvestmentAccount());
statement.getInvAccount().get(0).getSecAccountStmt().add(new SecurityStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
// method to count the number of TransactionStatement
System.out.println("Size of TransactionStatement is : " + count(statement));
}
private static int count(Statement stmt) {
int countOfTransStmt = 0;
for (InvestmentAccount invAcc : stmt.getInvAccount()) {
if (invAcc != null) {
for (SecurityStatement secStmt : invAcc.getSecAccountStmt()) {
if (secStmt != null) {
countOfTransStmt = countOfTransStmt + secStmt.getTransactionStatement().size();
}
}
}
}
return countOfTransStmt;
}
In Java 7 you're not going to do better than two for loops. I wouldn't bother with anything different.
In Java 8 you can use streams to flatten it out:
private static int count(Statement stmt) {
return stmt.getInvAccount().stream()
.filter(Objects::nonNull)
.flatMap(InvestmentAccount::getSecAccountStmt)
.filter(Objects::nonNull)
.flatMap(SecurityStatement::getTransactionStatement)
.count();
}
I would encourage you to get rid of the null checks. If you're going to ignore nulls, better to just expect them not to be inserted in the first place. It'll get rid of a lot of extra if checks throughout your code, I expect.
I'd also encourage you not to abbreviate your variables and methods. Spell out "statement" and "investment" and the like. The abbreviations are harder to read and the brevity isn't really a win.
Similarly, try to use more descriptive method names. countTransactions is better for the main method. And for the various getters, methods that return lists ought to be plural: "getAccounts" rather than "getAccount". Notice how the getters now match the class names; if you know the class name, you know the getter name. You don't have to guess if one or the other is abbreviated:
private static int countTransactions(Statement statement) {
return statement.getInvestmentAccounts().stream()
.flatMap(InvestmentAccount::getSecurityStatements)
.flatMap(SecurityStatement::getTransactionStatements)
.count();
}
Recursion could work in this case:
General idea below:
private int countTransactions(object t)
{
int sum = 0;
if (t == null) return 0;
for (int i = 0; i < t.getAllSub().count; i++)
{
sum += countTransactions(t.subAt(i));
}
return sum;
}
Hello everyone I'm writing a Java program where I need to copy the values of an old object into a new one (the two must be separated, if I chance one, the other must not be affected);
Once the copy is done the data should be displayed on Jtable, however the 2 object created seems to be linked(if I try to change one the other get modified too)
I suspect the problem is this method :
public void CopiatoreDiArea(Area nuova, Area daCopiare){
nuova.setNome(daCopiare.getNome());
nuova.setInter(daCopiare.getInter());
nuova.setRischioInerente(daCopiare.getRischioInerente());
nuova.setRischioResiduo(daCopiare.getRischioResiduo());
nuova.setControlli(daCopiare.getChecklists());
nuova.setStrategicita(daCopiare.getStrategicita());
nuova.setRischiosita(daCopiare.getRischiosita());
nuova.setMediaHpReato(daCopiare.getMediaHpReato());
nuova.setProbabilitaInerente(daCopiare.getProbabilitaInerente());
nuova.setEsposta(daCopiare.isEsposta());
nuova.setStrumentale(daCopiare.isStrumentale());
nuova.setCommento(daCopiare.getCommento());
nuova.setCondivisa(daCopiare.isCondivisa());
if (daCopiare.getNomeCompleto() != null){
nuova.setNomeCompleto(daCopiare.getNomeCompleto());
}
else{
nuova.setNomeCompleto(daCopiare.getNome());
}
if (daCopiare.getInterCompany() != null){
nuova.setInterCompany(daCopiare.getInterCompany());
}
if (daCopiare.getArticoli() != null || daCopiare.getArticoli().size() != 0){
nuova.setArticoli(daCopiare.getArticoli());
}
}
If this is the wrong way, how can I accomplish that?
How do you create the new instance of nuova object?
You have to make a new instance of it, if you created the new object with the reference of the oldest they will be linked and every change in the one will be reflected in other.
If you call the method as following:
CopiatoreDiArea(new Area(), oldArea)
Your code should work as the new 'Area' has all the attributes the other object has without any references being made to the new Area.
Try this:
public Area CopiatoreDiArea(Area daCopiare){
Area nuova = new Area();
nuova.setNome(daCopiare.getNome());
nuova.setInter(daCopiare.getInter());
nuova.setRischioInerente(daCopiare.getRischioInerente());
nuova.setRischioResiduo(daCopiare.getRischioResiduo());
nuova.setControlli(daCopiare.getChecklists());
nuova.setStrategicita(daCopiare.getStrategicita());
nuova.setRischiosita(daCopiare.getRischiosita());
nuova.setMediaHpReato(daCopiare.getMediaHpReato());
nuova.setProbabilitaInerente(daCopiare.getProbabilitaInerente());
nuova.setEsposta(daCopiare.isEsposta());
nuova.setStrumentale(daCopiare.isStrumentale());
nuova.setCommento(daCopiare.getCommento());
nuova.setCondivisa(daCopiare.isCondivisa());
if (daCopiare.getNomeCompleto() != null){
nuova.setNomeCompleto(daCopiare.getNomeCompleto());
}
else{
nuova.setNomeCompleto(daCopiare.getNome());
}
if (daCopiare.getInterCompany() != null){
nuova.setInterCompany(daCopiare.getInterCompany());
}
if (daCopiare.getArticoli() != null || daCopiare.getArticoli().size() != 0){
nuova.setArticoli(daCopiare.getArticoli());
}
}
And then in your call:
Area nuova = CopiatoreDiArea(daCopiare);
If you copy primitives (or the special primitive wrapper classes) in Java, the runtime will always do a deep copy of the values. To illustrate this, I show a few examples.
See http://jdoodle.com/a/3TL for an online runnable version of the code below:
public class MyClass {
public static void main(String[] args) {
int a = 10;
int b = a;
b = 20;
System.out.println(a + " != " + b);
// We did not change a when changing b.
Integer c = 10;
Integer d = c;
d = 20;
System.out.println(c + " != " + d);
// We did not change c when we changed d, even though they are class instances.
// This shows that primitive wrappers are handled differently due to
// autoboxing.
// See https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html
MyInteger e = new MyInteger(10);
MyInteger f = e;
f.value = 20;
System.out.println(e + " == " + f);
// Changing the data contained within f also affected e. The two variables now point to the same instance.
MyInteger g = new MyInteger(10);
MyInteger h = new MyInteger(g);
h.value = 20;
System.out.println(g + " != " + h);
// We prove that we have two instances, initially containing
// the same value but changing their internal values does not
// affect each other.
}
private static class MyInteger {
public int value;
public MyInteger(int value) {
this.value = value;
}
public MyInteger(MyInteger other) {
this.value = other.value;
}
public String toString() {
return Integer.toString(this.value);
}
}
}
From your example, it seems you might be trying to copy complex classes, even lists maybe, and these will always copy a reference only when you use simple assignment.
There are a few options that you could take, for instance the copy constructor that I use above, or alternatively rely on some form of reflection or serialization that does the hard work for you.
Apache Commons Lang has a SerializationUtils class that will run through all internal data in your classes, serialize them into byte format and then try to re-instantiate new versions of the same classes with the serialized data.
The Cloner library makes use of reflection and some special performance cases for known types such as collections and calendars, with some great debugging options.
Declare a copy constructor for deep cloning your object
public class Area {
public Area() { // constructor }
public Area(Area objectToCopy) {
setNome(objectToCopy.getNome());
setInter(objectToCopy.getInter());
setRischioInerente(objectToCopy.getRischioInerente());
setRischioResiduo(objectToCopy.getRischioResiduo());
setControlli(objectToCopy.getChecklists());
setStrategicita(objectToCopy.getStrategicita());
setRischiosita(objectToCopy.getRischiosita());
setMediaHpReato(objectToCopy.getMediaHpReato());
setProbabilitaInerente(objectToCopy.getProbabilitaInerente());
setEsposta(objectToCopy.isEsposta());
setStrumentale(objectToCopy.isStrumentale());
setCommento(objectToCopy.getCommento());
setCondivisa(objectToCopy.isCondivisa());
if (objectToCopy.getNomeCompleto() != null)
setNomeCompleto(objectToCopy.getNomeCompleto());
else
setNomeCompleto(objectToCopy.getNome());
if (objectToCopy.getInterCompany() != null)
setInterCompany(objectToCopy.getInterCompany());
if (objectToCopy.getArticoli() != null || objectToCopy.getArticoli().size() != 0)
setArticoli(objectToCopy.getArticoli());
}
}
and then do it calling
Area newArea = new Area(oldArea);
I was making a rock paper scissors game and I'm supposed to save the last four throws of the user into a HashMap. The last four throws will be inside a Pattern class. I have it so that if the pattern is already in the HashMap, then the value will be incremented by one, showing that the user have repeated that pattern one time. The patterns will be used to predict the user next move. However, when I compare the two patterns, the one in the HashMap and the one I just passed in, even though they are not the same, it returns that they are the same. I have tried looking into this for a while but I couldn't find out what's wrong. Some help would be greatly appreciated! The error comes right at the second input. If I input R, it will save it in the HashMapbut when I input anything else, it will throw a NullPointerException, which I think because the new pattern is not stored inside the hashmap but I tried to get the value of it since the program thinks that it is equal to the one already inside the HashMap. I think the problem is inside the equals() in Pattern but I'm not entirely sure.
import java.util.*;
public class RockPaperScisors{
public static void main(String[] args){
Scanner key = new Scanner(System.in);
Pattern pattern = new Pattern();
Pattern pattern1;
Computer comp = new Computer();
boolean stop = false;
int full=0;;
while ( !stop ){
System.out.println("Enter R P S. Enter Q to quit.");
char a = key.next().charAt(0);
if ( a == 'Q' ){
stop = true;
break;
}
pattern.newPattern(a);
char[] patt = pattern.getPattern();
for ( int i = 0; i < patt.length; i++ ){
System.out.print(patt[i] + " ");
}
pattern1 = new Pattern(patt);
comp.storePattern(pattern1);
System.out.println();
System.out.println("Patterns: " + comp.getSize());
full++;
}
}
}
import java.util.*;
public class Pattern{
private char[] pattern;
private int full = 0;
public Pattern(){
pattern = new char[4];
}
public Pattern(char[] patt){
pattern = patt;
}
public char[] getPattern(){
return pattern;
}
public void newPattern(char p){
if ( full <= 3 ){
pattern[full] = p;
full ++;
}
else{
for (int i = 0; i <= pattern.length-2; i++) {
pattern[i] = pattern[i+1];
}
pattern[pattern.length-1] = p;
}
}
public int HashCode(){
char[] a = pattern;
return a.hashCode();
}
public boolean equals( Object o ) {
if( o == this ) { return true; }
if(!(o instanceof Pattern)){ return false; }
Pattern s = (Pattern) o;
if (Arrays.equals(s.getPattern(), pattern))
System.out.println("Yes");
return Arrays.equals(s.getPattern(), pattern);
}
}
import java.util.*;
import java.util.Map.Entry;
public class Computer{
private HashMap<Pattern, Integer> map;
public Computer(){
map = new HashMap <Pattern, Integer>();
}
public void storePattern(Pattern p){
boolean contains = false;
for (Entry<Pattern, Integer> entry : map.entrySet())
{
Pattern patt = entry.getKey();
if ( p.equals(patt) ){
contains = true;
}
}
if ( contains ){
int time = map.get(p);
time++;
map.put(p, time);
}
else
map.put(p, 0);
}
public int getSize(){
return map.size();
}
}
Your HashCode is wrong.
It should be written in lower case.
public int hashCode()
In order to make sure that the method is overwritten, use the #Override annotation.
As noted by another answer, the first thing to do is rename and annotate your hashcode() method.
And then, you also have to fix it. It uses
char[] a = pattern;
return a.hashCode();
This means it uses the char[] object's hashCode() function. But that function is inherited directly from Object, and gives you a different hash code for two equal character arrays. For example, try this:
char[] c = { 'a','b','c' };
char[] d = { 'a','b','c' };
System.out.printf("%d %d%n", c.hashCode(), d.hashCode());
And you'll see that it prints two different numbers.
So you need to use a better hash code function. You can make your own, or use Arrays.hashCode(pattern) (there is no need for the local a variable). The important thing is that when two Patterns are equal according to the equals() method, they should have the same hash code.
What happens in your case is that you look up the HashCode by testing equality of all the entry keys (I'll get to that in a minute, it's a bad thing to do), so equals tell you you have the same key in the hash map. But the hash map itself uses the hashCode() method in get() to locate the object. And according to the hashCode() method, there is no object in the hash map that has the same key!
So they must always agree when the objects are equal.
Now, as for your method of looking up the object:
boolean contains = false;
for (Entry<Pattern, Integer> entry : map.entrySet())
{
Pattern patt = entry.getKey();
if ( p.equals(patt) ){
contains = true;
}
}
if ( contains ){
int time = map.get(p);
time++;
map.put(p, time);
} else
map.put(p, 0);
This is not how you use a Map. The whole point of a HashMap is that you can see if it contains a certain key or not in O(1). What you are doing is iterating it and comparing - and that`s O(N), very wasteful.
If you implement your hashCode() properly, you can just look it up by doing map.containsKey(p) instead of that loop. And if you are certain that you are not putting null values in the map, you can simply use get() to get your pattern:
Integer time = map.get(p);
if ( time == null ) {
map.put( p, 0 );
} else {
map.put( p, time+1);
}
(You don't need to use ++, because you are not actually using time after you put it in the map).
It's entirely possible that the issue in Pattern#HashCode.
The first issue is that it's not being used (it should be Pattern#hashCode), the second is that it's not calculating what you think it is.
You may find java.util.Arrays#hashCode very useful, changing the backing from an array to a List would also work.
As a side note, Pattern is not a great choice for the name of that class, as it clashes with java.util.regex.Pattern. This is more of a problem in this case than it might be otherwise, as it can be used with Scanner.
My Java code:
if(wins.containsKey(winner)) {
int currentCount = wins.get(winner);
wins.remove(winner);
wins.put(winner, currentCount + 1);
} else {
wins.put(winner, 1);
}
This was my alternative to something I can do in PHP and even C#:
if(isset($something[$key])) {
$something[$key]++;
} else {
$something[$key] = 1;
}
This is going to be used in a high number of iterations in a for loop so I would like to consider performance. Is this whole remove() then puts() business killing the performance? What is an alternative?
Your code can be replaced to:
if(wins.containsKey(winner)) {
wins.put(winner, wins.get(winner) + 1);
} else {
wins.put(winner, 1);
}
No need to remove the entry. When you add another entry in the map with same key, it will overwrite the existing one.
The way I usually do this to be as efficient as possible is:
Integer val = wins.get(winner);
wins.put(winner,val == null ? 1 : (val + 1));
This is very clean to me and avoids the extra hash lookup to "get" the val after you know it's already in there from the contains.
Firstly, I strongly suspect that this isn't going to be a performance bottleneck. As ever, test the simplest code that works before you use more complicated code.
You could use AtomicInteger instead of Integer as the value type of your map. That would allow you to mutate the wrapped value, rather than replacing the whole entry. Then you'd have:
if(wins.containsKey(winner)) {
wins.get(winner).incrementAndGet();
} else {
wins.put(winner, new AtomicInteger(1));
}
If you can stick with Integer, you could still optimize your code further:
Integer previousValue = wins.get(winner);
int newValue = previousValue == null ? 1 : (int) previousValue + 1;
wins.put(winner, newValue);
Now there is exactly one get and one put operation on each iteration.
I am new to java and I want to create a very simple "word completion " program. I will be reading in a dictionary file and recursively adding the words into a Node array (size 26). I believe I have managed to do this successfully but I am not sure how to go through and print the matches. For the sake of testing, I am simply inserting 2 words at the moment by calling the function. Once everything is working, I will add the method to read the file in and remove junk from the word.
For example: If the words "test" and "tester" are inside the tree and the user enters "tes", it should display "test" and "tester".
If somebody could please tell me how to go through and print the matches (if any), I would really appreciate it. Full code is below.
Thank you
What you implemented is called "trie". You might want to look at the existing implementations.
What you used to store child nodes is called a hash table and you might want to use a standard implementations and avoid implementing it yourself unless you have very-very specific reasons to do that. Your implementation has some limitations (character range, for example).
I think, your code has a bug in method has:
...
else if (letter[val].flag==true || word.length()==1) {
return true;
}
If that method is intended to return true if there are strings starting with word then it shouldn't check flag. If it must return true if there is an exact match only, it shouldn't check word.length().
And, finally, addressing your question: not the optimal, but the simplest solution would be to make a method, which takes a string and returns a node matching that string and a method that composes all the words from a node. Something like this (not tested):
class Tree {
...
public List<String> matches(CharSequence prefix) {
List<String> result = new ArrayList<>();
if(r != null) {
Node n = r._match(prefix, 0);
if(n != null) {
StringBuilder p = new StringBuilder();
p.append(prefix);
n._addWords(p, result);
}
}
return result;
}
}
class Node {
...
protected Node _match(CharSequence prefix, int index) {
assert index <= prefix.length();
if(index == prefix.length()) {
return this;
}
int val = prefix.charAt(index) - 'a';
assert val >= 0 && val < letter.length;
if (letter[val] != null) {
return letter[val].match(prefix, index+1);
}
return null;
}
protected void _addWords(StringBuilder prefix, List<String> result) {
if(this.flag) {
result.add(prefix.toString());
}
for(int i = 0; i<letter.length; i++) {
if(letter[i] != null) {
prefix.append((char)(i + 'a'));
letter[i]._addWords(prefix, result);
prefix.delete(prefix.length() - 1, prefix.length());
}
}
}
}
Maybe a longshot here, but why don't you try regexes here? As far as i understand you want to match words to a list of words:
List<String> getMatches(List<String> list, String regex) {
Pattern p = Pattern.compile(regex);
ArrayList<String> matches = new ArrayList<String>();
for (String s:list) {
if (p.matcher(s).matches()) {
matches.add(s);
}
}
return matches
}